Does Spring Data JPA automatically create cache for query method? - spring

I created query method in Spring Data JPA repository. I used method naming conventions.
I'm not sure but it looks like Spring Data made query cache for it. I have those entity:
public class Feature {
private String desc;
private FeatureFor featureFo;
}
public enum FeatureFor {
ABC, DEF, XYZ;
}
In repository I created method with name:
public List<Feature> findByFeatureForIn(List<FeatureFor> featureFors);
This method is invoked twice from different servises.
First time when it's invoked I can see generated query in console which is something like this:
SELECT ...... WHERE ((t0.featureFor = ? OR t0.featureFor = ?) AND t0.featureFor IS NOT NULL) [params=(String) ABC, (String) DEF]
This is ok. But When method is invoked via second service I can see same select generated with the same parameters. I'm sure that in featureFors parameter there were ABC and XYZ. But it's completely ignored. I also tried to use featureFors with one ABC value contained in (in first invoked service). In this case query generated was something like this:
SELECT ...... WHERE (t0.featureFor = ? AND t0.featureFor IS NOT NULL) [params=(String) ABC, (String) DEF]
Second service passed same params (ABC and XYZ) but the generated query and params did not change (it's same which generated in the first service). Does anybody knows if Spring Data creates cache for queries? I didn't realize I made some mistake. Maybe I did. I'm using OpenJPA. Thank you for your help.
The persistence configuration looks like this:
<?xml version="1.0"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="openjpa">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<class>...difened entities here (including Feature)...</class>
<properties>
<property name="openjpa.Log" value="DefaultLevel=INFO, Runtime=INFO, Tool=INFO, SQL=TRACE"/>
<property name="openjpa.ConnectionFactoryProperties" value="PrintParameters=true" />
<property name="openjpa.jdbc.MappingDefaults" value="ForeignKeyDeleteAction=restrict,JoinForeignKeyDeleteAction=restrict"/>
</properties>
</persistence-unit>
</persistence>

Related

Cannot manually Instantiate class inside Component annotated class

I am in the process of understanding the Spring and I stumbled with these peculiar things.
I Have the Component annotated class below named MyComponent (please disregard the interface), and that Class uses the HelperClass. This helper class was instantiated manually twice for two different variables inside the method named doSomething
I also have my bean project-properties.xml that was also imported in app-config.xml
Yes, there is a Bean for HelperClass for some reason and it also has an Initial value every time it's been #autowired, and even if it is instantiated it manually and that value is from the bean xml.
#Component
public MyCompontent implement MyInterface {
public doSomething() {
HelperClass helper1 = new HelperClass();
HelperClass helper2 = new HelperClass();
// print the value set by helper1 and its not null, the value is from bean xml
System.out.println(helper1.getVariable1);
helper1.setVariable1("Set Value for Helper1");
helper2.setVariable1("Set Value for Helper2");
// print the value set by helper1 but it display the value of the helper 2
System.out.println(helper1.getVariable1);
}
}
public HelperClass {
private String variable1;
private String variable2;
public void variable1(String variable1){
this.variable1 = variable1
}
public String getvariable1() {
return this.variable1;
}
public void variable2(String variable2){
this.variable2 = variable2
}
public String getvariable2() {
return this.variable2;
}
}
project-properties.xml
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myHelper" class="com.example.HelperClass">
<property name="variable1" value="bean-value1"/>
<property name="variable1" value="bean-value2"/>
</bean>
</beans>
app-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
...........
<!-- Configures Spring MVC -->
<import resource="project-properties.xml"/>
.....
.....
</beans>
My Questions are:
I understand that if I use #autowired on HelperClass it will have properties values from bean's XML, but why is it still happening even if I manually Instantiate this class(HelperClass helper = new HelperClass())?
What is the mechanism of spring behind this?
Can I disable this thing or prevent it to happen in a specific class?
Even if I instantiated it multiple times, why are they still pointing or referencing into a Single instance of HelperClass? It sounds like its scope is Singleton.
If I ever get the answer to previous questions, my next question is how can I perfectly instantiate HelperClass without reference to the bean, what I mean is how can I disable those things to happen on a specific line in a class?
If you feel that my question is redundant please help me to redirect
Thanks and Regards
There is a very high probability that you have been misled by your printings.
Spring can autowire dependencies if class has such annotation on constructor, field, or setter. Spring does not control the instances that have been created manually.
Spring can't even get inside your method, because the framework (in standard case) operates with the interface of your class using reflections. On startup, the framework goes through all the classes, finds all the annotations that have to be processed, and covers such classes with proxies (almost always). But Spring never goes inside your code directly, it can't put a new line of its code in between of 2 your lines in the same method.

How to use static variable as value for named-native-query inside JPA?

I want to use static variable as a query for a named-native-query inside JPA (persistence.xml) file.
I'm using Spring boot 2.1.9 and hibernate 5.3.12.
I have an interface :
public interface SqlQueryFacture {
String MEMOIRES_TABLE_BY_FACTURE = "SELECT ......";
}
and I want to use MEMOIRES_TABLE_BY_FACTURE as value in persistence.xml file like this
<entity-mappings version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm
http://xmlns.jcp.org/xml/ns/persistence/orm_2_2.xsd">
<entity class="fr.pp.entities.factures.Facture">
<named-native-query name="Facture.getMemoiresTableByFactureId" result-set-mapping="MemoireTableRowDtoMapping">
<query>SqlQueryFacture.MEMOIRES_TABLE_BY_FACTURE</query>
</named-native-query>
</entity>
</entity-mappings>
Can I do that without use #NamedNativeQuery inside the entity class ?
I'm guessing that you are trying for dynamic queries through JPA. Unfortunately, JPA doesn't provide support for dynamic queries.
You can't do in JPA (persistence.xml) :
<query>SqlQueryFacture.MEMOIRES_TABLE_BY_FACTURE</query>
For example :
<!-- Query takes HQL (Hibernate Query Language) directly -->
<query>SELECT p from Product p</query>
This is allowed.

Aspect around advice not triggering on controller

I have an aspect advice that tracks the execution of classes annotated with #Service. The code is currently working but I would like to change it to track REST endpoints on controllers instead of autowired services. Here is the code:
#Aspect
public class AuditingAspect
{
#Pointcut(
//TODO Change pointcut from public methods in Services to REST endpoints in Controllers
"execution(public * my.base.package..*.*(..))" //Must be in package
//+ " && #within(org.springframework.stereotype.Service)" //Has to be a service
+ " && #within(org.springframework.stereotype.Controller)" //Has to be a controller
)
public void auditLoggingPointCut() {
//no op
}
#Around(value ="auditLoggingPointCut()")
public Object logAround(final ProceedingJoinPoint joinPoint) throws Throwable
{
System.out.println("Exection");
returnVal = joinPoint.proceed();
// Now Do The After Logging Part
afterReturningLog(joinPoint, returnVal) ;
return returnVal;
}
private void afterReturningLog(final JoinPoint joinPoint, final Object returnValue)
{
System.out.println("Exiting");
}
}
When I change the "within" from #Service to #Controller, I don't see any output from the advice but the method executes when accessed from the URL. What is different about a Controller that would ignore execution?
The Controller class looks like this:
#Controller
public class CaseReferralEndpoints {
#Autowired
CaseReferralFacade caseReferralFacade;
#RequestMapping(value="/backgroundcheck/getcasereferrals", method = RequestMethod.GET)
#ResponseBody
public List<CaseReferralSection> getCaseReferrals(#RequestParam("caseID") Long caseID) {
return caseReferralFacade.getCaseReferrals(caseID);
}
}
Here is my applicationContext-aop.xml The full config is much larger but I believe this is the most relevant.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean class="gov.dhs.uscis.elis2.backend.services.logging.AuditingAspect"/>
<aop:aspectj-autoproxy proxy-target-class="false" />
</beans>
Supposing that your #within configuration is correct, a potential remedy to your troubles would be the following:
<aop:aspectj-autoproxy proxy-target-class="true" />
Also you will have to add CGLIB to your classpath
The above steps are needed since your controller does not implement an interface
Finally if you have a root context and a web context, the aop related stuff needs to be applied to the web context (having it in the root context will not work for the controllers that are configured in the web context)
UPDATE
In Gradle to add CGLIB to the classpath add:
'cglib:cglib:2.2.2'
In Maven it would be:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
Error was found inside of the applicationContext.xml
My controllers were being filtered out of context scanning! I'm one of many developers on the project so I did not think to look here initially.
<context:component-scan>
<!-- a bunch of packages -->
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
However, I ended up adding an Interceptor which has proven to be closer to what I wanted. Because all of our user actions are REST driven it was easier and cleaner to audit the invocation of REST calls than try and track autowired service methods.
As your pointcut expression is having
#within(org.springframework.stereotype.Service)
with && symbol , advice is going to apply only within your package upto service.
and i hope your controller class is not inside ..Service package, it might be inside
.*.*Controller package so its not executing for controller
solution
Remove within inside point cut expression
or add controller also inside point cut expression
Assuming your pointcut is correct, and you are using two spring contexts, one for the services/daos (appcontext) and one for the controllers (servletcontext), my tip goes in the direction of misconfiguration.
AOP configuration is one of the spring beans which are applied ONLY inside the context it is declared/scanned.
So assuming you have a servletcontext.xml for your controllers your pointcuts wont be applied unless you declare the aop context configuration within this context.
(The application context declaration will be needed if you want to apply the pointcuts to your services.)

Updated entity not being retrieved correctly

I have a spring mvc application running on glassfish. I don't know the source of my problem so ill elaborate as much as possible. I have 2 Classes
A User Class
#Entity
#Table(name="Users")
public class User extends BaseEntity<User> {
// other fields
#OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
#OrderBy(value = "id DESC")
private Set<OtherClass> objs;
// getters and setters
}
and an OtherClass:
#Entity
#Table(name="OtherObjects")
public class OtheClass extends BaseEntity<OtheClass> {
// other fields
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "User", nullable = false)
private User user;
// getters and setters
}
i retrieve a user object when the application starts and put it in the session object. while runtime, the user can add to the DB a "OtherClass" object. the otherClass object is saved correctly in the DB (with a relation to the correct user row in the Users table). the thing is that after the user added the otherClass object at runtime, the Set of other objects doesn't update. the weirder thing is that even if i retrieve the user object from the DB again, i don't get the updated Set of OtherClass.
This is my persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="myPU" transaction-type="JTA">
<jta-data-source>jdbc/MyDataSource</jta-data-source>
<class>org.company.entities.OtherClass</class>
<class>org.company.entities.User</class>
<exclude-unlisted-classes />
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.current_session_context_class" value="thread" />
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider" />
<property name="hibernate.hbm2ddl.auto" value="create" />
</properties>
</persistence-unit>
</persistence>
I recently changed my transaction manager from the jpa transaction manager of spring to JTA transaction manager. (i suppose it has something to do with it). Any ideas? if further code or configuration is required, please tell and i'll post an update.
JPA doesn't maintain bidirectional associations automatically, it's up to the developer to update both sides of the relationship. In this case upon creating the OtherClass object you should add it to the objs collection in the User object.

In Spring MVC 3.0.5 controller JPA entity not getting persisted to the database

In the code below, persist() returns w/o an exception but the entity is not stored in the database.
#RequestMapping(method = RequestMethod.POST)
public String form() {
EntityManager em = this.emf.createEntityManager();
TaxRates t = new TaxRates();
t.setCountry("US");
// set more properties
em.persist(t);
em.close();
...
}
persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="TT-SpringMVCPU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
...
<class>com.sajee.db.TaxRates</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:jtds:sqlserver://localhost:1234/mydb"/>
<property name="javax.persistence.jdbc.password" value="Password1"/>
<property name="javax.persistence.jdbc.driver" value="net.sourceforge.jtds.jdbc.Driver"/>
<property name="javax.persistence.jdbc.user" value="sa"/>
</properties>
</persistence-unit>
</persistence>
I don't need any transaction support or any fancy enterprise feature support. I simply want to create an entity and save it to the database.
Where am I going wrong?
persist() doesn't write your object to the database immediately. Instead, it marks your object as persistent, so that it will be written to the database before transaction commit (or before executing a query, or during explicit flush() operation).
So, even if you don't need transactional behaviour you still have to manage transactions. You can do it manually as follows:
#RequestMapping(method = RequestMethod.POST)
public String form() {
EntityManager em = this.emf.createEntityManager();
TaxRates t = new TaxRates();
t.setCountry("US");
// set more properties
em.getTransaction().begin();
em.persist(t);
em.getTransaction().commit();
em.close();
...
}
But Spring's declarative transaction support is a more convenient way to do it.

Resources