I am fairly new to both Hibernate3 and Spring3, and I'm having an issue related to initializing lazy references of a hibernate object.
I have a fully contained dao and service. The domain objects are created using hbm2java and a reverse engineering file. I have followed some best practices I have found using Annotations (@Transactional) on my service objects. (This guide was VERY helpful to me http://carinae.net/2009/11/layered-architecture-with-hibernate-and-spring-3/)
The issue that I am having is that I have the following spring configuration in my service.jar for annotation processing and transaction management:
<context:annotation-config />
<context:component-scan base-package="com.barlingbay.dodmerb.persistence" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</bean>
<tx:annotation-driven/>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
My hibernate.cfg.xml is simply a listing of my datasource details and the annotation mappings of the domain objects.
I am using a service layer and a dao layer.
@Service
public class ApplicantEventServiceImpl implements ApplicantEventService {
@Autowired(required = true)
private ApplicantEventDao appEventDao;
@Transactional
public List<ApplicantEvent> getEvents() {
return this.appEventDao.getPendingEvents();
}
and a dao layer
@Repository
public class ApplicantEventDaoImpl implements ApplicantEventDao {
@Autowired(required = true)
private SessionFactory sessionFactory;
public List<ApplicantEvent> getPendingEvents() {
sessionFactory.getCurrentSession().beginTransaction(); // (If I don't have this, my junit test fails because of no active transaction, but that's a different issue)
return sessionFactory.getCurrentSession()
.createQuery("from ApplicantEvent").list();
}
This collection of code is packaged as a maven module and is included in as a dependency in another spring project which is a scheduling and workflow module that I am developing. Relevant applicationContext.xml info
<bean id="workflowStepper" class="com.barlingbay.merb.scheduler.WorkflowStepper" />
<bean id="jobDetailWorkflowStepper"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"
p:targetObject-ref="workflowStepper" p:targetMethod="execute" />
<bean id="triggerJobDetailTicketRegistryCleaner" class="org.springframework.scheduling.quartz.SimpleTriggerBean"
p:jobDetail-ref="jobDetailWorkflowStepper" p:startDelay="2000"
p:repeatInterval="5000" />
<bean id="scheduler"
class="com.barlingbay.merb.scheduler.AutowiringSchedulerFactoryBean" />
And a basic Workflow.java:
public class WorkflowStepper implements IWorkflowStepper,
ApplicationContextAware {
private final Logger LOG = Logger.getLogger(this.getClass());
private ApplicationContext applicationContext;
// @Transactional
public void execute() {
ApplicantEventService appEvent = (ApplicantEventService) applicationContext
.getBean("applicantEventServiceImpl");
List<ApplicantEvent> events = appEvent.getEvents();
for (ApplicantEvent event : events) {
try {
LOG.info(event.getApplicant().getUsername() + "[" + event.getName()
+ "]");
....
I get (and I understand why I get) a LazyInitializationException during the LOG.info statement. The transaction is managed by the spring-hibernate context in the included service maven dependency and is not available in this context. What I don't understand is the proper way to include the transaction management into this layer (and beyond) to prevent the LazyInitializationException. I tried simply adding
<bean id="txInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor" />
to the business layer's application context, which it complained that it couldn't see the transactionmanager defined in the service dependency. However, if I do add @Transactional to the .execute() of the Workflow stepper, it does "inherit" the configuration from the dependency.
What am I missing?