Problems with Opensessioninviewer + JPA + Tomcat standard

Asked

Viewed 115 times

3

Hello, I am using Tomcat + JPA + Vraptor 4 and I am 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 in the Controller, the connection is opened and closed normally. However, if you are 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 from Entitymanagercreator, the listing works, but the connection is kept open.

If I trigger a cdi event, and use @Inject Serverdao the connection remains open.

How can I close the connection, or use a better approach without the default Opensessioninview?

1 answer

3

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

And as the Job/Task of your Quartz probably has a different scope the Injection does not work (because of NullPointer). This is the ultimate proof of why OpenSessionInView / OpenEntitymanagerInView is a anti-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, closer to the state-of-the-art, are to use some CDI-Extension (such as Delta-Spike, p/ex.) that does the Injection of EntityManager according to the JSR-specification; or use the vRaptor JPA plugin.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.