Problems with the OpenSessionInViewer + JPA + Tomcat standard

3

Hello, I'm using Tomcat + JPA + Vraptor 4 and I'm using cdi to inject EntityManager as follows.

EntityManagerFactoryCreator:

public class EntityManagerFactoryCreator {
    @ApplicationScoped
    @Produces
    public EntityManagerFactory getEntityManagerFactory(){
        return Persistence.createEntityManagerFactory("default");
    }

    public void destroy(@Disposes EntityManagerFactory factory){
       if(factory.isOpen()){
           factory.close();
       }
    }
}

EntityManagerCreator:

public class EntityManagerCreator {
   private EntityManagerFactory factory;

  /**
   *  @depreciated CDI eyes only
   */
    public EntityManagerCreator() {}

    @Inject
    public EntityManagerCreator(EntityManagerFactory factory) {
        this.factory = factory;
    }

    @Produces @RequestScoped
    public EntityManager getEntityManager(){
       return factory.createEntityManager();
    }

    public void destroy(@Disposes EntityManager entityManager){
       if(entityManager.isOpen()){
          entityManager.close();
       }
    }
}

GenericDAO:

public abstract class DAO < T > {
/**
* EntityManager
*/
@
Inject private EntityManager em;

/**
* Faz referência aos DAOS
*/
private Class < T > clazz;

public DAO() {
        clazz = getClazz();
}

@
Transactional
public boolean create(T entity) {
        try {
                em.getTransaction().begin();
                em.persist(entity);
                em.getTransaction().commit();
                return true;
        } catch (Exception e) {
                return false;
        }
}

@
Transactional
public boolean update(T entity) {
        try {
                em.getTransaction().begin();
                em.merge(entity);
                em.getTransaction().commit();
                return true;
        } catch (Exception e) {
                return false;
        }
}

public T getById(Long id) {
        return em.find(clazz, id);
}

@
Transactional
public boolean remove(Long id) {
        try {
                T entity = em.find(clazz, id);
                em.getTransaction().begin();
                em.remove(entity);
                em.getTransaction().commit();
                return true;
        } catch (Exception e) {
                return false;
        }
}

public List < T > list() {
        try {
                return em.createQuery("FROM " + clazz.getName(), clazz).getResultList();
        } catch (Exception e) {
                return null;
        }
}

@
SuppressWarnings("unchecked")
private Class < T > getClazz() {

        Class <? > classeDAO = this.getClass();

        while (classeDAO.getSuperclass() != DAO.class) {
                classeDAO = classeDAO.getSuperclass();
        }

        ParameterizedType tipo = (ParameterizedType) classeDAO.getGenericSuperclass();

        Class < T > clazz = null;

        try {
                clazz = (Class < T > ) tipo.getActualTypeArguments()[0];
        } catch (ClassCastException exception) {
                throw exception;
        }
        return clazz;
}
}'

When the ServerDAO class is instantiated on the Controller, the connection is opened and closed normally. However, if it is instantiated in a Quartz Job for example and try to make a list with the list () method, the following error occurs.

  

19: 16: 01,662 ERROR [TaskLogger] Task serverTask was failed   java.lang.NullPointerException   at br.com.serverus.tasks.ServerTask.execute (ServerTask.java:36)   at br.com.serverus.tasks.ServerTask $ Proxy $$$ WeldClientProxy.execute (Unknown Source)   at br.com.caelum.vraptor.tasks.jobs.simple.ConcurrentJobWrapper.execute (ConcurrentJobWrapper.java:20)   at org.quartz.core.JobRunShell.run (JobRunShell.java:202)   at org.quartz.simpl.SimpleThreadPool $ WorkerThread.run (SimpleThreadPool.java:573)

If I remove the @RequestScoped property of EntityManagerCreator, the listing works, but the connection is kept open.

If I trigger an event from the cdi, and use the @Inject ServerDAO the connections remain open.

How can I close the connection, or use a better approach without the OpenSessionInView standard?

    
asked by anonymous 28.07.2016 / 02:30

1 answer

3

The problem is that if you put the Producer from EntityManager to @RequestScoped , it only instantiated and injected into dependencies of instances that have just that same scope.

And since your Quartz's Job / Task probably has a different scope than Injection does not work (on account of NullPointer ). This is the full proof of why OpenSessionInView / OpenEntitymanagerInView is an anti -pattern and is one of the reasons why it should be avoided whenever possible. Try changing the scope (from Producer) to @Dependent

If this does not work, the solutions, which are closer to the state of the art, are to use some CDI Extension (such as Delta-Spike, for example) to Injection% JSR; or use the vPAaptor JPA plugin.

    
01.06.2018 / 22:11