I'm currently working on a job that do automates a subscription process from an input file.
So I have a class:
@Startup
@Singleton
public class ImportSubscriptionsJob implements Job {
//calls ImportSubscriptionsJobBean
}
The Singleton class calls a stateless class:
@Stateless
public class ImportSubscriptionsJobBean {
@PersistenceContext
private EntityManager em;
//we need a transaction
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
@Interceptors({ JobLoggingInterceptor.class })
public void execute() {
//calls another stateless class with em injected
}
}
And this class calls another stateless class and so on. Some of the classes are annotated with @LocalBean because of cyclic dependency, so they need to be injected via: @EJB.
The entityManager are pass from level 2 to nth.
The problem right now is on the nth level service call, I'm encountering the error below. This is the hierarchy:
Singleton[1]->Stateless (TX=REQUIRES_NEW)[2]->Stateless (TX=REQUIRES_NEW)[3]->Stateless[4]->Stateless[5]->Stateless[6]->Stateless[7]
On the 6th level it calls a method from 7th level that simply query for entityX:
List<X> Xs = getQuery(em).getResultList();
And that is when the error is thrown.
Any idea?
Last set of lines from the stacktrace:
Caused by: org.hibernate.HibernateException: illegally attempted to associate a proxy with two open Sessions
at org.hibernate.proxy.AbstractLazyInitializer.setSession(AbstractLazyInitializer.java:123) [hibernate-core-4.2.7.SP1-redhat-3.jar:4.2.7.SP1-redhat-3]
at org.hibernate.engine.internal.StatefulPersistenceContext.reassociateProxy(StatefulPersistenceContext.java:629) [hibernate-core-4.2.7.SP1-redhat-3.jar:4.2.7.SP1-redhat-3]
at org.hibernate.engine.internal.StatefulPersistenceContext.reassociateIfUninitializedProxy(StatefulPersistenceContext.java:588) [hibernate-core-4.2.7.SP1-redhat-3.jar:4.2.7.SP1-redhat-3]
at org.hibernate.event.internal.ProxyVisitor.processEntity(ProxyVisitor.java:49) [hibernate-core-4.2.7.SP1-redhat-3.jar:4.2.7.SP1-redhat-3]
Note that my transaction is container manage so I'm wondering why I'm getting this error :-?
If I retain only one REQUIRES_NEW in the first Stateless class, I'm getting:
JBAS011469: Transaction is required to perform this operation (either use a transaction or extended persistence context)
But why when all my classes are annotated with Stateless? By default it's a session bean and all methods can start a new tx if does not exists.
The problem is this:
If you have 2 REQUIRES_NEW then there are going to be two transactions open during your flow and probably you associate the same entity with two concurrent sessions.
Try changing the transaction propagation to REQUIRES.
From a transaction management point of view, the only difference between a stateful and a state-less EJB is when you have entity references in your stateful EJB fields, or when you employ an extended persistence context. In that case it's much more difficult to mix those two. When calling a stateless EJB from a stateful one you need to pass it the entities as method arguments.
As for the transaction propagation I see no reason why you can't use the same transaction for all such calls. In fact that's mandatory for having a single atomic unit-of-work.