Como faço para configurar corretamente um EntityManager em um aplicativo jersey / hk2?

Eu tenho um aplicativo jersey-2 / hk2 que usa persistência JPA. O EntityManager está ligado na boot como este

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

com a class de fábrica sendo

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

isso funciona, mas, para cada solicitação, recebo um aviso nos logs sobre um EntityManager já 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' 

O que estou fazendo de errado? Qual é a maneira correta de inicializar um EntityManager em um aplicativo jersey-2 / hk2?

Uma opção é, em vez de criar um novo EntityManagerFactory no EMFactory (que está em um escopo de solicitação), você pode criar uma fábrica de singletons para o EntityManagerFactory , em seguida, apenas inserir o EntityManagerFactory no 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; } ... } 

Não testou esta implementação exata, mas deve ser algo como isto. Eu usei esse padrão 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); } }); 

ATUALIZAR

Uma coisa a notar sobre o exemplo acima é que ele não limpa resources, ou seja, o EntityManager deve estar próximo; não se fechará. Há um método de dispose na class Factory que precisamos ignorar, mas, de acordo com minha experiência, isso nunca é chamado por Jersey.

O que podemos fazer é adicionar o EntityManager a um [ 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; } ... } 

Desta forma, o EntityManager é garantido para ser fechado no final do pedido.