Search code examples
jpajakarta-eeejbcdi

What are the limitations of @Transactional in CDI?


I am trying to use a @Transactional method inside a CDI class, instead of an EJB:

@javax.inject.Named
// fails @javax.enterprise.context.ApplicationScoped
// fails @javax.enterprise.context.SessionScoped
// works @javax.ejb.Singleton
// works @javax.ejb.Stateless
public class SomeClass {
    @javax.persistence.PersistenceContext
    private EntityManager em;

    @javax.annotation.PostConstruct    
    @javax.transaction.Transactional
    public void someMethod() {
        em.persist(someEntity);
    }
}

When I annotate SomeClass with @Singleton or @Stateless, everything works.

When I annotate SomeClass with @ApplicationScoped or @SessionScoped, WildFly 13 displays the following error message:

Transaction is required to perform this operation (either use a transaction or extended persistence context)

I was under the impression that @Transactional works with CDI since Java EE 7. Have I been mistaken? Or am I simply missing some additional configuration?


Solution

  • I'll try to give a short list of things to look when trying to make @Transactional work with CDI, so as to give the answer a bit more value than the comment:

    1. We are discussing javax.transaction.Transactional, not javax.ejb.TransactionAttribute, which works for EJBs!
    2. It does NOT work out-of-the-box in non-JEE applications!
    3. And by JEE applications we mean those running a full JEE application server; Tomcat out-of-the-box does NOT support it!
    4. Beware of classpath problems, specifically make sure no jar containing the annotation javax.transaction.Transactional exists e.g. in WEB-INF/lib, when running in a full JEE application server. If you want to utilize it in a non-full-JEE environment, you will need to have it in the classpath.
    5. @Transactional is implemented as a CDI interceptor by the latest JTA specifications. As such:
      • It's not there in JEE < 7!
      • It has the same limitations as any interceptor. E.g. it cannot be called for initializer methods - @PostConstruct [THIS WAS THE PROBLEM IN THIS QUESTION], and it is NOT activated when invoking methods of this object, BEWARE!!!
    6. I am quite confident that more errors may exist!!!