How do I properly configure an EntityManager in a jersey / hk2 application?

dependency-injection, hk2, java, jersey-2.0, jpa

Solution

One option is to instead of creating a new `EntityManagerFactory` in the `EMFactory` (which is in a request scope), you could create a singleton factory for the `EntityManagerFactory`, then just inject the `EntityManagerFactory` into the `EMFactory`.

public class EMFFactory implements Factory<EntityManagerFactory> {
    private final EntityManagerFactory emf;
    public EMFFactory (){
        emf = Persistence.createEntityManagerFactory(persistenceUnit);
    }
    public EntityManagerFactory provide() {
        return emf;
    }
    ...
}

public class EMFactory implements Factory<EntityManager> {
    private final EntityManager em;

    @Inject
    public EMFactory (EntityManagerFactory emf){
        em = emf.createEntityManager();
    }
    public EntityManager provide() {
        return em;
    }
    ...
}

Haven't tested this exact implementation out, but it should look something like this. I've used this pattern before.

register(new AbstractBinder() {
    @Override
    public void configure() {
      bindFactory(EMFFactory.class).to(EntityManagerFactory.class).in(Singleton.class);
      bindFactory(EMFactory.class).to(EntityManager.class).in(RequestScoped.class);
    }
});

UPDATE

One thing to note about the above example is that it doesn't clean up resources, i.e. the `EntityManager` should be close; it won't close itself. There is a `dispose` method in the `Factory` class that we need to override, but from my experience, this is never called by Jersey.

What we can do is add the `EntityManager` to a [`CloseableService`][1]

public class EMFactory implements Factory<EntityManager> {
    private final EntityManagerFactory emf;
    private final CloseableService closeService;

    @Inject
    public EMFactory (EntityManagerFactory emf, CloseableService closeService){
        this.emf = emf;
        this.closeService = closeService;
    }
    public EntityManager provide() {
        final EntityManager em = emf.createEntityManager();
        this.closeService.add(new Closeable(){
            @Override
            public void close() {
                em.close();
            }
        });
        return em;
    }
    ...
}

This way the `EntityManager` is ensured to be closed at the end of the request.

Problem

I have a jersey-2 / hk2 application which uses JPA persistence. The `EntityManager` is bound at startup like this ``` public MyApplication() { // ... register(new AbstractBinder() { @Override public void configure() { bindFactory(EmFactory.class) .to(EntityManager.class) .in(RequestScoped.class); } }); } ``` with the factory class being ``` public class EmFactory implements Factory<EntityManager> { private static final String PERSISTENCE_UNIT = "unit"; private EntityManagerFactory emf; private CloseableService closeableService; @Inject public EmFactory(@Named(PERSISTENCE_UNIT) String persistenceUnit, CloseableService closeableService) { emf = Persistence.createEntityManagerFactory(persistenceUnit); this.closeableService = closeableService; } @Override public EntityManager provide() { final EntityManager entityManager = emf.createEntityManager(); closeableService.add(new Closeable() { @Override public void close() throws IOException { if(entityManager.isOpen()) { entityManager.close(); } } }); return entityManager; } @Override public void dispose(EntityManager entityManager) { if(entityManager.isOpen()) { entityManager.close(); } } } ``` this works but then for each request i get a warning in the logs about an EntityManager being already registered: ``` HHH000436: Entity manager factory name (unit) is already registered. \ If entity manager will be clustered or passivated, specify a unique \ value for property 'hibernate.ejb.entitymanager_factory_name' ``` What am I doing wrong? What is the proper way to initialize an EntityManager in a jersey-2 / hk2 application?

Original source

Related problems