2011-01-16 22 views
38

que tiene una guerra que contenga lo siguiente:PersistenceContext EntityManager NullPointerException inyección

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> 

Mi clase TestServlet es el siguiente :

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(); 
    } 
}

Cuando se invoca el método get() obtengo una NullPointerException; el EntityManager no ha sido inyectado. ¿Alguna sugerencia sobre lo que podría extrañar o cómo puedo diagnosticarlo? Hay muy poco en el registro del servidor.

Estoy seguro de que esto funcionaba sin el jboss-web.xml o la entrada del origen de datos en web.xml. Implementé el ds.xml en el directorio de implementación por separado también, y eso definitivamente ha mejorado: puedo verlo en la consola JMX.

Intenté usar JBoss 4.2.3 y una versión 6.0 con el mismo resultado.

+0

¿Adivina que hay problemas con la publicación de XML en las secciones de código? – rich

+0

Tendría que escapar < and > -> <y> – adrianboimvaser

+3

Nunca lo he probado en la práctica, así que no me fije en él, pero ¿es realmente posible ejecutar JPA en una aplicación web declarada como Servlet? 2.3 (J2EE 1.3) en lugar de Servlet 2.5 (Java EE 5, cuando se introdujo JPA por primera vez)? – BalusC

Respuesta

70

Un administrador de entidades solo se puede inyectar en clases que se ejecutan dentro de una transacción. En otras palabras, solo se puede inyectar en un EJB. Otros classe deben usar EntityManagerFactory para crear y destruir un EntityManager.

Como su TestService no es un EJB, la anotación @PersistenceContext simplemente se ignora. No solo eso, en JavaEE 5, no es posible inyectar un EntityManager ni una EntityManagerFactory en un servicio JAX-RS. Tienes que ir con un servidor JavaEE 6 (JBoss 6, Glassfish 3, etc.).

He aquí un ejemplo de la inyección de 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(); 
     } 
    } 
} 

La forma más fácil de ir aquí es declarar su servicio como un EJB 3.1, asumiendo que usted está utilizando un servidor Java EE 6.

pregunta relacionada: Inject an EJB into JAX-RS (RESTful service)

+1

Gracias, problema similar sin embargo en que obtengo un NPE en esta línea:

 EntityManager entityManager = entityManagerFactory.createEntityManager(); 
rich

+0

¡Gracias, esto funcionó para mí! Estoy usando CXF 2.7.5, Hibernate 4.x, Spring 3.x y JPA 2.x. –

+0

Por favor déjenme saber por qué no puedo inyectar un administrador de entidades en beans sin estado @PersistenceContext (unitName = "Tester2PU") emityManager em privado; en tomcat 7.0.27 es nulo. gracias senthil – user1503117

2

Si el componente es un EJB, entonces, no debería haber un problema de inyección de una EM.

Pero .... En JBoss 5, la integración JAX-RS no es excelente. Si tiene un EJB, no puede usar el escaneo y debe enumerarlo manualmente en el context-param resteasy.jndi.resource. Si todavía tiene el escaneo activado, Resteasy buscará la clase de recurso y lo registrará como un servicio JAX-RS de vanilla y manejará el ciclo de vida.

Este es probablemente el problema.

Cuestiones relacionadas