I'm working on migrating my existing EJB project from Jersey 1.x to Jersey 2.x. I'm facing the exception while trying to execute my EJB Queries. After some research I'm able to find out that issue is with the EntityManager configuration.
In Existing Jersey 1.x code, we configure EnitityManager in the below way,
@PersistenceContext(unitName = "datasource")
private EntityManager em;
em.createQuery("SELECT e FROM Employee e WHERE e.userName = :userName").setParameter("userName", userName).getSingleResult();
But my EJB query is not working, resulting in Internal Server Exception.
When I changed the Entity Manager configuration in below way, it worked
private static EntityManager em;
static {
em = Persistence.createEntityManagerFactory("datasource").createEntityManager();
}
My question here is,
1) Is this the right way to do ?
2) is there any specific procedure to configure EntityManager in Jersey 2?
UPDATE:
I learned through this link How do I properly configure an EntityManager in a jersey / hk2 application? and implemented in the following way and it worked
Class implementing Entity Manager Factory:
public class EMFactory implements Factory<EntityManagerFactory> {
private final EntityManagerFactory emf;
public EMFactory () {
emf = Persistence.createEntityManagerFactory("datasource");
}
@Override
public void dispose(EntityManagerFactory emf) {}
@Override
public EntityManagerFactory provide() {
return emf;
}
}
Class implementing Entity Manager:
public class MyEntityManager implements Factory<EntityManager> {
private final EntityManager em;
@Inject
public MyEntityManager (EntityManagerFactory emf) {
em = emf.createEntityManager();
}
@Override
public void dispose(EntityManager em) {
if (em.isOpen()) {
em.close();
}
}
@Override
public EntityManager provide() {
return em;
}
Binded these classes to Abstract Binder:
public class ApplicationBinder extends AbstractBinder {
@Override
protected void configure() {
bindFactory(EMFactory .class).to(EntityManagerFactory.class).in(Singleton.class);
bindFactory(MyEntityManager .class).to(EntityManager.class).in(RequestScoped.class);
}
Loaded the Binder and mapped this loader class in web.xml
public class BinderLoader extends ResourceConfig {
public BinderLoader() {
register(new ApplicationBinder());
packages(true, "com.package.resources");
}
}
Used the Entity Manager in the following way:
@Inject
private javax.inject.Provider<EntityManager> emFactory;
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public UserVO getUser(String userName) {
EntityManager em = emFactory.get();
user = (User) em.createQuery("SELECT u FROM User u WHERE u.userName = :userName").setParameter("userName", userName).getSingleResult();
}
But my question is everytime when emFactory.get() is called, new instance is created. This affects my application's performance. Is there any solution to create a single instance of EntityManager and use across where ever needed ?