Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 765
agnul Avatar asked Jan 20 '15 12:01

agnul


People also ask

How do I get EntityManager from EntityManagerFactory?

Step 2: Obtaining an Entity Manager From a Factory EntityManager entityManager = entityManagerFactory. createEntityManager(); EntityManager — An EntityManager is an interface. createEntityManager() method — It creates a new application-managed EntityManager.

What is difference between EntityManager and EntityManagerFactory?

EntityManagerFactory vs EntityManagerWhile EntityManagerFactory instances are thread-safe, EntityManager instances are not. The injected JPA EntityManager behave just like an EntityManager fetched from an application server's JNDI environment, as defined by the JPA specification.

How does EntityManager work in JPA?

In JPA, the EntityManager interface is used to allow applications to manage and search for entities in the relational database. The EntityManager is an API that manages the lifecycle of entity instances. An EntityManager object manages a set of entities that are defined by a persistence unit.

What is EntityManager and EntityManagerFactory in JPA?

Several entity manager factories can be prepared for connecting to different data stores. JPA EntityManager is used to access a database in a particular application. It is used to manage persistent entity instances, to find entities by their primary key identity, and to query over all entities.


1 Answers

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.

like image 107
Paul Samsotha Avatar answered Nov 15 '22 01:11

Paul Samsotha