Getting a reference to EntityManager in Java EE applications using CDI

persistence context vs entitymanager
persistencecontext entitymanager example
spring data jpa entitymanager example
entitymanagerfactory
what is entitymanager
getentitymanager
create entitymanagerfactory

I'm using Java EE 7. I would like to know what is the proper way to inject a JPA EntityManager into an application scoped CDI bean. You can't just inject it using @PersistanceContext annotation, because EntityManager instances are not thread safe. Let's assume that we want our EntityManager to be created at the beginnig of every HTTP request processing and closed after the HTTP request is processed. Two options come into my mind:

1. Create a request scoped CDI bean which has a reference to an EntityManager and then inject the bean into an application scoped CDI bean.

import javax.enterprise.context.RequestScoped;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@RequestScoped
public class RequestScopedBean {

    @PersistenceContext
    private EntityManager entityManager;

    public EntityManager getEntityManager() {
        return entityManager;
    }
}

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;

@ApplicationScoped
public class ApplicationScopedBean {

    @Inject
    private RequestScopedBean requestScopedBean;

    public void persistEntity(Object entity) {
        requestScopedBean.getEntityManager().persist(entity);
    }
}

In this example an EntityManager will be created when the RequestScopedBean is created, and will be closed when the RequestScopedBean is destroyed. Now I could move the injection to some abstract class to remove it from the ApplicationScopedBean.

2. Create a producer that produces instances of EntityManager, and then inject the EntityManager instance into an application scoped CDI bean.

import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

public class EntityManagerProducer {

    @PersistenceContext
    @Produces
    @RequestScoped
    private EntityManager entityManager;
}

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;

@ApplicationScoped
public class ApplicationScopedBean {

    @Inject
    private EntityManager entityManager;

    public void persistEntity(Object entity) {
        entityManager.persist(entity);
    }
}

In this example we will also have an EntityManager which is created every HTTP request, but what about closing the EntityManager? Will it also be closed after the HTTP request is processed? I know that the @PersistanceContext annotation injects container-managed EntityManager. This means that an EntityManager will be closed when a client bean is destroyed. What is a client bean in this situation? Is it the ApplicationScopedBean, which will never be destroyed until the application stops, or is it the EntityManagerProducer? Any advices?

I know I could use a stateless EJB instead of application scoped bean and then just inject EntityManager by @PersistanceContext annotation, but that's not the point :)

You're almost right on with your CDI producer. Only thing is that you should use a producer method instead of a producer field.

If you're using Weld as CDI container (GlassFish 4.1 and WildFly 8.2.0), then your example of combining @Produces, @PersistenceContext and @RequestScoped on a producer field should throw this exception during deployment:

org.jboss.weld.exceptions.DefinitionException: WELD-001502: Resource producer field [Resource Producer Field [EntityManager] with qualifiers [@Any @Default] declared as [[BackedAnnotatedField] @Produces @RequestScoped @PersistenceContext com.somepackage.EntityManagerProducer.entityManager]] must be @Dependent scoped

Turns out that the container is not required to support any other scope than @Dependent when using a producer field to lookup Java EE resources.

CDI 1.2, section 3.7. Resources:

The container is not required to support resources with scope other than @Dependent. Portable applications should not define resources with any scope other than @Dependent.

This quote was all about producer fields. Using a producer method to lookup a resource is totally legit:

public class EntityManagerProducer {

    @PersistenceContext    
    private EntityManager em;

    @Produces
    @RequestScoped
    public EntityManager getEntityManager() {
        return em;
    }
}

First, the container will instantiate the producer and a container-managed entity manager reference will be injected into the em field. Then the container will call your producer method and wrap what he returns in a request scoped CDI proxy. This CDI proxy is what your client code get when using @Inject. Because the producer class is @Dependent (default), the underlying container-managed entity manager reference will not be shared by any other CDI proxies produced. Every time another request want the entity manager, a new instance of the producer class will be instantiated and a new entity manager reference will be injected into the producer which in turn is wrapped in a new CDI proxy.

To be technically correct, the underlying and unnamed container who do the resource injection into the field em is allowed to reuse old entity managers (see footnote in JPA 2.1 specification, section "7.9.1 Container Responsibilities", page 357). But so far, we honor the programming model required by JPA.

In the preceding example, it would not matter if you mark EntityManagerProducer @Dependent or @RequestScoped. Using @Dependent is semantically more correct. But if you put a wider scope than request scope on the producer class you risk exposing the underlying entity manager reference to many threads which we both know is not a good thing to do. The underlying entity manager implementation is probably a thread-local object, but portable applications cannot rely on implementation details.

CDI does not know how to close whatever stuff it is that you put into the request bound context. More so than anything else, a container-managed entity manager must not be closed by application code.

JPA 2.1, section "7.9.1 Container Responsibilities":

The container must throw the IllegalStateException if the application calls EntityManager.close on a container-managed entity manager.

Unfortunately, many people do use a @Disposes method to close the container-managed entity manager. Who can blame them when the official Java EE 7 tutorial provided by Oracle as well as the CDI specification itself use a disposer to close a container-managed entity manager. This is simply wrong and the call to EntityManager.close() will throw a IllegalStateException no matter where you put that call, in a disposer method or somewhere else. The Oracle example is the biggest sinner of the two by declaring the producer class to be a @javax.inject.Singleton. As we learned, this risk exposing the underlying entity manager reference to many different threads.

It has been proven here that by using CDI producers and disposers wrongfully, 1) the not thread-safe entity manager may be leaked to many threads and 2) the disposer has no effect; leaving the entity manager open. What happened was the IllegalStateException which the container swallowed leaving no trace of it (a mysterious log entry is made which says there was an "error destroying an instance").

Generally, using CDI to lookup container-managed entity managers is not a good idea. The application is most likely better off just using @PersistenceContext and be happy with it. But there are always exceptions to the rule like in your example, and CDI can also be useful to abstract away the EntityManagerFactory when handling the life cycle of application-managed entity managers.

To get a complete picture on how to obtain a container-managed entity manager and how to use CDI to lookup entity managers, you might want to read this and this.

Using CDI/Weld to Inject JPA/Hibernate Entity Managers, Java Platform, Enterprise Edition (Java EE) 7 with the current JTA transaction, and EntityManager references that With an application-managed entity manager, on the other 37.3.1.3 Finding Entities Using the EntityManager CDI Applications · 25.2 Using Alternatives in CDI Applications. The crux of the matter of any CDI-based JPA application is the creation of an injectable entity manager. It’s worth noting that regardless of the approach that we use to get the manager, once it becomes an injectable Java EE resource, the entirety of the examples shown in the rest of the post are equally valid.

I understand your problem. but that is not a real one. Do not get messed up with the CDI declared scope of a containing class, that will propagate the scope of the attributes expect those that use @Inject'ion!

The @Inject'ed will compute their reference in depencency of the CDI-declaration of the implementation class. So you might have Applicationscoped class with a @Inject EntityManager em inside, but each controlflow will find its own em-transaction reference to a disjount em-object, because of the EntityManager CDI declaration of the implementation class behind.

The wrong thing of your code is, that you provide an inner getEntityManager() access method. Do not pass Injected object, if you need one, simply @Inject it .

37.3 Managing Entities, CDI is integrated with the major component technologies in Java EE, namely: To enable a Web application to use a bean that injects another bean class, the Injecting the reference to the entity manager factory by using the producer field  Create a request scoped CDI bean which has a reference to an EntityManager and then inject the bean into an application scoped CDI bean. import javax . enterprise . context . RequestScoped ; import javax . persistence .

You should use the @Dispose annotation to close the EntityManager, as in the example below:

@ApplicationScoped
public class Resources {

    @PersistenceUnit
    private EntityManagerFactory entityManagerFactory;

    @Produces
    @Default
    @RequestScoped
    public EntityManager create() {
        return this.entityManagerFactory.createEntityManager();
    }

    public void dispose(@Disposes @Default EntityManager entityManager) {
        if (entityManager.isOpen()) {
            entityManager.close();
        }
    }

}

9 Using Contexts and Dependency Injection for the Java EE Platform, What do I need to do to get @PersistenceContext working in Weld? All managed beans may take advantage of Java EE component environment injection I think the main use case of CDI is for applications that use JPA. In a Java EE 6 application server - where this integration is defined by the other Java EE specifications. Does this mean we have to run JBoss 6 or Glassfish v3, both are in beta? I think your response above will drastically hurt CDI's adoption rate. I think the main use case of CDI is for applications that use JPA.

You may inject savely EntityManagerFactory, it is thread save

@PersistenceUnit(unitName = "myUnit")
private EntityManagerFactory entityManagerFactory;

then you can retrive EntityManager from entityManagerFactory.

How do I get a JPA EntityManager reference in W |JBoss.org , The most common and widely used entity manager in a Java EE environment JBoss Seam 3 is built on top of CDI and has at it's core concept the notion of In a Java SE environment only extended context application-managed entity managers are available. You can get this reference using the getReference() method. Although Spring is the major player in this field, what makes particularly attractive CDI is that it's part of the Java EE 6 stack, thus any container which is Java EE 6 compatible can run an application using CDI. If you want to have an introduction to CDI you can look at this former tutorial.

Hibernate EntityManager, Obtaining CDI beans via dependency injection, with support for all the That example project uses Weld as the CDI container, Hibernate ORM as the JPA provider (the CDI reference implementation) aimed at the purposes of testing. integration tests in a Java EE (or should I say, Jakarta EE) container. Obtenir une référence à EntityManager dans les applications Java EE en utilisant CDI J'utilise Java EE 7. Je voudrais savoir quelle est la bonne façon d'injecter un JPA EntityManager dans un application étendue CDI bean.

Testing CDI Beans and the Persistence Layer Under Java SE, The JPA-Entity Season represents a Training Season (e.g. all units of I always had a bad feeling - because obtaining a reference from an JPA-Entities through a You can download the whole application from http://p4j5.dev.java.net entitymanager inside a jpa entity these days using JavaEE 6/JPA 2? CDI (Contexts and Dependency Injection) is a standard dependency injection framework included in Java EE 6 and higher. It allows us to manage the lifecycle of stateful components via domain-specific lifecycle contexts and inject components (services) into client objects in a type-safe way.

Why sometimes a reference to an EntityManager inside JPA Entities , A JPA @Entity bean is used with the EntityManager to create, persist and merge data to a <persistence xmlns="http://java.sun.com/xml/ns/persistence" version=​"1.0"> The @PersistenceContext annotation can be used on any CDI bean, EJB, application "/Users/dblevins/examples/injection-of-entitymanager" loaded. The idea of using CDI for testing purposes is not new actually. You can find several examples on the Internet about how to test applications that solely uses CDI. However, we want to test a Java EE Application. Since you mostly have EJBs in a Java EE application, using CDI alone won’t help you with that.

Comments
  • You're creating an application-managed entity manager (which must be closed by the application code). The question was about container-managed entity managers.
  • I can do that and then get EntityManager from factory in every method of application scoped bean. But will it be a container-managed EntityManager? I don't think so. I don't want to manage the lifecycle of an EntityManager and transactions on my own.
  • @FlyingDumpling what version of java EE do you use? If prior to Java EE 7 you do not have transactions support in CDI beans anyway. See this response: stackoverflow.com/questions/17838221/…
  • @AndreiI Sorry I didn't mention, I use Java EE 7