¿Cómo configuro correctamente un EntityManager en una aplicación jersey / hk2?

Tengo una aplicación jersey-2 / hk2 que usa persistencia JPA. El EntityManager está vinculado al inicio como este

 public MyApplication() { // ... register(new AbstractBinder() { @Override public void configure() { bindFactory(EmFactory.class) .to(EntityManager.class) .in(RequestScoped.class); } }); } 

con la clase de fábrica siendo

 public class EmFactory implements Factory { 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(); } } } 

esto funciona pero luego, para cada solicitud, recibo una advertencia en los registros acerca de que un EntityManager ya está registrado:

 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' 

¿Qué estoy haciendo mal? ¿Cuál es la forma correcta de inicializar un EntityManager en una aplicación jersey-2 / hk2?

Una opción es, en lugar de crear una nueva EntityManagerFactory en EMFactory (que está en un ámbito de solicitud), puede crear una fábrica de singleton para EntityManagerFactory , luego simplemente inyectar EntityManagerFactory en EMFactory .

 public class EMFFactory implements Factory { private final EntityManagerFactory emf; public EMFFactory (){ emf = Persistence.createEntityManagerFactory(persistenceUnit); } public EntityManagerFactory provide() { return emf; } ... } public class EMFactory implements Factory { private final EntityManager em; @Inject public EMFactory (EntityManagerFactory emf){ em = emf.createEntityManager(); } public EntityManager provide() { return em; } ... } 

No he probado esta implementación exacta, pero debería ser algo como esto. He usado este patrón antes.

 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); } }); 

ACTUALIZAR

Una cosa a tener en cuenta sobre el ejemplo anterior es que no limpia los recursos, es decir, el EntityManager debe estar cerca; no se cerrará solo. Hay un método de dispose en la clase de Factory que necesitamos anular, pero desde mi experiencia, nunca es llamado por Jersey.

Lo que podemos hacer es agregar EntityManager a [ CloseableService ] [1]

 public class EMFactory implements Factory { 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; } ... } 

De esta forma, se garantiza que EntityManager se cerrará al final de la solicitud.