web-dev-qa-db-fra.com

Injection de NullPointerException dans PersistenceContext EntityManager

J'ai une guerre contenant les éléments suivants:

META-INF/MANIFEST.MF
WEB-INF/classes/META-INF/persistence.xml
WEB-INF/classes/com/test/service/TestServlet.class
WEB-INF/classes/com/test/service/TestEntity.class
WEB-INF/classes/jndi.properties
WEB-INF/classes/postgresql-ds.xml
WEB-INF/jboss-web.xml
WEB-INF/web.xml
index.jsp

persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://Java.Sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://Java.Sun.com/xml/ns/persistence http://Java.Sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
    <persistence-unit name="test">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>Java:/TestDS</jta-data-source>

        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update" />
            <property name="hibernate.show_sql" value="true" />
        </properties>
    </persistence-unit>
</persistence>

web.xml:

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://Java.Sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Test Web Application</display-name>

    <context-param>
        <param-name>resteasy.scan</param-name>
        <param-value>true</param-value>
    </context-param>
    <listener>
        <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
    </listener>
    <servlet>
        <servlet-name>Resteasy</servlet-name>
        <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>Resteasy</servlet-name>
        <url-pattern>/service/*</url-pattern>
    </servlet-mapping>

    <resource-ref>
        <res-ref-name>TestDS</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
        <res-sharing-scope>Shareable</res-sharing-scope>
    </resource-ref>
</web-app>

Ma classe TestServlet est la suivante:

package com.test.service;

import Java.util.*;
import javax.persistence.*;
import javax.ws.rs.*;

@Path("/service")
public class TestService {

    @PersistenceContext(unitName = "test")
    private EntityManager em;

    @GET
    @Path("/get")
    @Produces("application/json")
    public List get() {
        return em.createQuery("from TestEntity").getResultList();
    }
}

Lorsque la méthode get () est appelée, j'obtiens une exception NullPointerException. EntityManager n'a pas été injecté. Des suggestions sur ce que je pourrais manquer ou comment je peux le diagnostiquer? Il y a très peu dans le journal du serveur.

Je suis sûr que cela fonctionnait sans jboss-web.xml ni l'entrée de source de données dans web.xml. J'ai également déployé le fichier ds.xml dans le répertoire de déploiement séparément, ce qui est clairement pris en compte - je peux le voir dans la console JMX.

Essayé d'utiliser JBoss 4.2.3 et une version 6.0 avec le même résultat.

43
rich

Un gestionnaire d'entités ne peut être injecté que dans des classes s'exécutant dans une transaction. En d'autres termes, il ne peut être injecté que dans un EJB. Les autres classes doivent utiliser EntityManagerFactory pour créer et détruire un EntityManager.

Puisque votre TestService n'est pas un EJB, l'annotation @PersistenceContext est simplement ignorée. De plus, dans JavaEE 5, il n'est pas possible d'injecter un EntityManager ni un EntityManagerFactory dans un service JAX-RS. Vous devez utiliser un serveur JavaEE 6 (JBoss 6, Glassfish 3, etc.).

Voici un exemple d'injection d'un EntityManagerFactory:

package com.test.service;

import Java.util.*;
import javax.persistence.*;
import javax.ws.rs.*;

@Path("/service")
public class TestService {

    @PersistenceUnit(unitName = "test")
    private EntityManagerFactory entityManagerFactory;

    @GET
    @Path("/get")
    @Produces("application/json")
    public List get() {
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        try {
            return entityManager.createQuery("from TestEntity").getResultList();
        } finally {
            entityManager.close();
        }
    }
}

Le moyen le plus simple consiste à déclarer votre service en tant que EJB 3.1, en supposant que vous utilisez un serveur JavaEE 6.

Question associée: Injecter un EJB dans JAX-RS (service RESTful)

76
Andre Rodrigues

Si le composant est un EJB, alors, l'injection d'un EM ne devrait pas poser de problème.

Mais .... Dans JBoss 5, l'intégration JAX-RS n'est pas géniale. Si vous avez un EJB, vous ne pouvez pas utiliser la numérisation et vous devez répertorier manuellement le contexte-param resteasy.jndi.resource. Si vous avez toujours le contrôle en cours, Resteasy recherchera la classe de ressources et l'enregistrera en tant que service Vanilla JAX-RS et gérera le cycle de vie.

C'est probablement le problème.

2
Bill Burke