I have a service class annotated with #Transactional calling a DAO layer method to return an object with a collection on it lazily loaded. When I then try and initialize this collection in the service layer using Hibernate.inititialize(..), hibernate doesn't load the collection. The DAO is configured to use entity manager and the object class is annotated with JPA annotations. I have the following spring application context..
<beans xmlns="http://www.springframework.org/schema/beans"...">
<orcl:pooling-datasource id="dataSource" url="..." username="..." password="..."/>
<context:annotation-config/>
<!-- Hibernate entity manager -->
<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="org.gmp.webapp.model" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean id="dao" class="org.gmp.webapp.dao.impl.HibDAOImpl" />
</beans>
My DAO interface and implementaionn...
package org.gmp.webapp.dao;
import java.util.List;
import org.gmp.webapp.model.Crime;
public interface DAO {
public Crime getCrime(String crimeNo);
}
import org.gmp.webapp.dao.DAO;
import org.gmp.webapp.model.Crime;
public class HibDAOImpl implements DAO {
#PersistenceContext
protected EntityManager em;
public Crime getCrime(String crimeNo) {
return this.em.find(Crime.class, crimeNo);
}
}
My object looks something like this..
#Entity
#Table(name="CRIME_TABLE")
public class Crime {
#Id
#Column(name = "CRIME_NO")
private String crimeNo;
#OneToMany
#JoinColumn(name="PER_CRIME_NO", referencedColumnName="CRIME_NO")
private List<PersonCrimeLink> personLinks;
....
public List<PersonCrimeLink> getPersonLinks() {
return personLinks;
}
}
The service class is annotated with transactional (spring) so I thought as the call to the DAO and the initialize were in the same transaction, this should work.
My service..
#Service
#Transactional(readOnly=true)
public class CrimeServiceImpl implements CrimeService {
#Autowired private CrimeDAO crimeDAO;
public Crime getCrime(String crimeNo) {
Crime crime = crimeDAO.getCrime(crimeNo);
Hibernate.initialize(crime.getPersonLinks());
return crime;
}
}
The collection is loaded when I run a test of the DAO method, when making a call to the getter for the collection. I have annotated the test method with #Transactional. The personLinks object is omitted but like I say it returns the records in the test. I think I am not understanding the transaction manager I am using as this process worked when I was using session factory and HibernateTransactionManager.
Many Thanks in advance for any guidance on this.
Just a quick tip on this, as you decided to use the JPA's EntityManagerFactory instead of the Hibernate's SessionFactory as your orm API, then i would stick to that API on other layers of the application.
That is, using the EntityManager to get the data and then switch to using the implementation API (Hibernate.initialize) is not a consistent / maintainable approach.
Like you said in the post, if you stick to the JPA specification, which is initializing collection once it is accessed for the first time then you do not get any errors and the list is loaded:
The LAZY strategy is a hint to the persistence provider runtime that
data should be fetched lazily when it is first accessed
So as of JPA specification, you only need to do this:
public Crime getCrime(String crimeNo) {
Crime crime = crimeDAO.getCrime(crimeNo);
crime.getPersonLinks().size(); // any access method
return crime;
}
Related
I want to interceptor to the data fetch from database using hibernate that if in my data, particular field is present then get the value and check if that value is applicable to the user who queried it.
My application uses spring mvc with hibernate. I have configured an interceptor at session factory level.
class AuditInterceptor extends EmptyInterceptor {
#Override
public Object instantiate(String entityName, EntityMode entityMode, Serializable id) {
System.out.println("******************************* instantiated ****************************");
return null;
}
#Override
public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
System.out.println("******************************* on load ****************************");
return true;
}
}
In my spring-dao.xml
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="c3p0DataSource" />
<property name="packagesToScan">
...
</property>
<property name="hibernateProperties">
....
</property>
<property name="entityInterceptor">
<bean class="com.hibernate.AuditInterceptor" />
</property>
</bean>
I want whenever query.list() excutes it should be able to intercept data using above inteceptor.
Now, it is calling my interceptor when my application starts. I am not able to get data for validation.(I want to perform validation in interceptor)
I am able to inject EntityManager in my Service class without defining any persistence-unit.
This is my configuration:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
<jpa:repositories base-package="com.example"></jpa:repositories>
In my Service class:
#PersistenceContext
private EntityManager entityManager;
// THIS WORKS!
final Session session = entityManager.unwrap(Session.class);
Is it because of the jpa:repositories ?
Spring ORM package's LocalContainerEntityManagerFactoryBean class makes this possible. It uses DefaultPersistenceUnitManager class to build an instance of PersistenceUnitInfo which can then be provided to PersistenceProvider class's createContainerEntityManagerFactory. Hibernate implements this interface so that Spring can create an instance of EntityMangerFactory class.
DefaultPersistenceUnitManager class is the one that creates a persistenceUnit called default and finds all the entity classes going through the classes on the classpath. Same information acquired from the persistence.xml has been taken in with a alternative approach like this without having a physical persistence.xml file.
Finally Spring uses JpaVendorAdapter configured to get the JPA provider- specific EntityManagerFactory instance.
Spring data JPA specific <jpa:repositories base-package="...." /> or #EnableJpaRepositories uses to scan all the beans annotated with #Repository to provide dynamic queries and other features. This is not an exhaustive explanation but you see how this "magic" happens.
You can find more on grepcode or download the sources to explore more.
I am refering to Spring AOP by Mkyong http://www.mkyong.com/spring/spring-aop-example-pointcut-advisor/
It worked when tried running from main (i.e. App.java) as given on above link,
I want to integrate it in restful webservice where i have multiple service like CutomerService in mkyong's example.
For example i have controller which calls CustomerService,
#RestController
#RequestMapping(value = "/customer")
public class CustomerController{
#Autowired CustomerService customerService;
#RequestMapping(value = "/getCustomer", method = RequestMethod.GET")
public ResponseEntity<CommonResponse> getService(){
customerService.printName();
}
}
It didn't worked.
i have tried this also:
#Autowired
private ProxyFactoryBean customerServiceProxy;
#RequestMapping(value = "/getCustomer", method = RequestMethod.GET")
public ResponseEntity<CommonResponse> getService(){
CustomerService customerService = (CustomerService) customerServiceProxy
.getTargetSource().getTarget();
customerService.printName();
}
}
this dosent work either.
Any Solution for this?
my bean-config.xml is same as mkyong's example.
It worked ! Just need to change proxy class from "org.springframework.aop.framework.ProxyFactoryBean" to
"org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"
Auto proxy creator identifies beans to proxy via a list of names. So we don,t need to specify target bean instead list of beans can be specified and it will intercept automatically.
My config look as below:
<bean id="adviceAround" class="com.tdg.ess.semantic.event.log.AdviceAround" />
<!-- Event logging for Service -->
<bean id="testServicePointCut" class="org.springframework.aop.support.NameMatchMethodPointcut">
<property name="mappedNames">
<list>
<value>process</value>
</list>
</property>
</bean>
<bean id="testServiceAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" ref="testServicePointCut" />
<property name="advice" ref="adviceAround" />
</bean>
<bean
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<!-- Differnt beans which have certain service defined like CustomerService-->
<value>testService1</value>
<value>testService2</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>testServiceAdvisor</value>
</list>
</property>
</bean>
Thanks everyone for looking into.
I am trying to implement the following: clear some details from DB on SpringSecurity logout handler. The main problem that after trying to get user details from DB I get this error. The rest of code and even the same method work fine in other cases.
public class CurrentUserLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
/**
*
*/
#Autowired
private RequestsService requestsService;
/**
*
*/
#Autowired
private OffersService offersService;
/**
*
*/
#Autowired
private UsersService usersService;
/**
*
*/
#Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
if (authentication != null) {
UserDetailsExtended details = (UserDetailsExtended) authentication.getPrincipal();
User user = usersService.get(details.getId()); // fails here
requestsService.unlockAllByBackoffice(user);
offersService.unlockAllByBackoffice(user);
}
setDefaultTargetUrl("/");
super.onLogoutSuccess(request, response, authentication);
}
}
Config:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.ejl.butler.object.data" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
<prop key="hibernate.cache.region.factory_class">${hibernate.cache.region.factory_class}</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
DAO:
public User get(final Long id) {
Session session = SessionFactoryUtils.getSession(sessionFactory, false);
return (User) session.get(User.class, id);
}
Spring security config:
<logout invalidate-session="true" logout-url="/logout" success-handler-ref="logoutSuccessHandler"/>
Exception:
No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
at org.springframework.orm.hibernate3.SessionFactoryUtils.doGetSession(SessionFactoryUtils.java:356)
at org.springframework.orm.hibernate3.SessionFactoryUtils.getSession(SessionFactoryUtils.java:202)
#Transactional resolves the problem but I can't understand why? I mean it fails only in this handler in all other calls this method works fine without this annotation!
Thank you in advance!
UPD:
My temporary solution is to add #Transactional to whole onLogoutSuccess method.. It works)
If you have defined a TransactionManager in your spring context you have to specify #Transactional somewhere in the stack. Otherwise you will get the exception you encountered because you are trying to run a query outside of a transaction.
There are workarounds to this such specifying current_session_context_class in your hibernate configuration to thread or
<property name="current_session_context_class">org.hibernate.context.ThreadLocalSessionContext</property>
but it's not production safe..
The possible values for current_session_context_class are jta, thread and managed. Further to that, jta and thread are supported by hibernate out of box. thread context is used in most stand alone hibernate apps or those based on light weight frameworks like Spring and jta is used in Java EE environments.
Also try sessionFactory.getCurrentSession() instead of SessionFactoryUtils.getSession().
here is some code from a post here that would explain my question:
Interface:
package org.better.place
public interface SuperDuperInterface{
public void saveWorld();
}
Implementation:
package org.better.place
import org.springframework.stereotype
public class SuperDuperClass implements SuperDuperInterface{
public void saveWorld(){
System.out.println("Done");
}
}
Client:
package org.better.place
import org.springframework.beans.factory.annotation.Autowire;
public class SuperDuperService{
private SuperDuperInterface superDuper;
public void doIt(){
superDuper.saveWorld();
}
public void setSuperDuper(SuperDuperInterface superDuper) {
this.superDuper = superDuper;
}
}
My question is - how can I configure the beans in the spring config? I don't want to use #Autowired and other annotations.
I guess it will be something like this:
<bean id="superService" class="org.better.place.SuperDuperService">
<property name="superDuper" ref="superWorker"
</bean>
<bean id="superWorker" class=?????? parent=???????? >
</bean>
You will have to instantiate the implementing class, of course:
<bean id="superWorker" class="org.better.place.SuperDuperClass"/>
You would only need the parent attribute if you wanted to create multiple beans with common properties that you don't want to repeatedly declare, so you move it to an abstract parent bean definition that the concrete bean definitions can reference.
Assuming the SuperDuperClass has some properties:
<bean id="superWorkerPrototype" abstract="true"
class="org.better.place.SuperDuperClass">
<property name="prop1" value="value1"/>
<property name="prop2" value="value2"/>
</bean>
<bean id="superWorker1" parent="superWorkerPrototype"
class="org.better.place.SuperDuperClass">
<property name="prop3" value="foo"/>
</bean>
<bean id="superWorker2" parent="superWorkerPrototype"
class="org.better.place.SuperDuperClass">
<property name="prop3" value="bar"/>
</bean>
Which would result in both instances having the same values for prop1 and prop2, but different ones for prop3.
You can just give the implementation class's fully qualified name, and its not required to give parent attribute. Spring will automatically find if it can assign an instance of SuperDuperClass to the superDuper field of SuperDuperService
<bean id="superWorker" class="org.better.place.SuperDuperClass" >
</bean>