1

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 ?

Community
  • 1
  • 1
Heisenberg
  • 147
  • 1
  • 4
  • 14
  • EntityManagers are not supposed to be reused as a singleton. Even in a container-managed situation, you will get a new EntityManager for each request. It is the EntityManagerFactory that is the expensive one to create. – Paul Samsotha Jan 17 '17 at 16:03
  • Also keep in mind that your transaction annotations have no affect. I'm assuming that you are coming from an EE server. These servers have full EE support, where you can use container managed JPA. Using standalone Jersey, you will not get this support. So you need to manage the transactions yourself. Otherwise maybe you want to just use another EE server. If you are already using an EE server (e.g. latest Glassfish), then you should not be trying to create the EM and EMF yourself, unless you really want this type of configuration. You should figure out why your server manage JPA isn't working. – Paul Samsotha Jan 17 '17 at 16:07
  • Thanks @peeskillet for your detailed explanation.This will help me a lot. – Heisenberg Jan 18 '17 at 14:41
  • Still I have 2 questions. 1) How can I close the EntityManagerFactory ? calling entityManagerFactory.close() inside the dispose() is enough for closing the emf? 2) Is there a way to register 2 datasources and get 2 entityManagers. even when we create the emf by speciying the datasource, when we use the EM in session classes we get the EM by doing @Inject private javax.inject.Provider emFactory; So how can we use 2 different entity managers in a single class? – Heisenberg Jan 18 '17 at 14:46
  • Able to resolve the Qus 1 by calling the emf.close() inside the dispose(). – Heisenberg Jan 19 '17 at 13:50
  • Any clue on Qus 2 ?? – Heisenberg Jan 19 '17 at 13:50
  • You can create two factories using names, and `bindFactory(..).to(..).named("....")`, then add `@Named("...")` to the injection – Paul Samsotha Jan 19 '17 at 14:04
  • Thanks peeskillet ! will try it – Heisenberg Jan 19 '17 at 14:12

0 Answers0