webentwicklung-frage-antwort-db.com.de

PersistenceContext EntityManager-Injektion NullPointerException

Ich habe einen Krieg, der folgendes beinhaltet:

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>

Meine TestServlet-Klasse lautet wie folgt:

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

Wenn die Methode get () aufgerufen wird, erhalte ich eine NullPointerException. Der EntityManager wurde nicht injiziert. Irgendwelche Vorschläge, was mir fehlen könnte oder wie ich es diagnostizieren kann? Das Serverprotokoll enthält sehr wenig.

Ich bin mir sicher, dass dies ohne die Datei jboss-web.xml oder den Datenquelleneintrag in der Datei web.xml funktioniert hat. Ich habe die Datei ds.xml auch separat im Bereitstellungsverzeichnis bereitgestellt und das ist definitiv erledigt - ich kann es in der JMX-Konsole sehen.

Versucht mit JBoss 4.2.3 und einem 6.0 Build mit dem gleichen Ergebnis.

43
rich

Ein Entitätsmanager kann nur in Klassen eingefügt werden, die in einer Transaktion ausgeführt werden. Mit anderen Worten, es kann nur in einen EJB injiziert werden. Andere Klassen müssen eine EntityManagerFactory verwenden, um einen EntityManager zu erstellen und zu löschen.

Da Ihr TestService kein EJB ist, wird die Annotation @PersistenceContext einfach ignoriert. Darüber hinaus ist es in JavaEE 5 nicht möglich, einen EntityManager oder eine EntityManagerFactory in einen JAX-RS-Dienst einzufügen. Sie müssen einen JavaEE 6-Server (JBoss 6, Glassfish 3 usw.) verwenden.

Hier ist ein Beispiel für das Injizieren einer 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();
        }
    }
}

Der einfachste Weg, hierher zu gelangen, besteht darin, Ihren Dienst als EJB 3.1 zu deklarieren, vorausgesetzt, Sie verwenden einen JavaEE 6-Server.

Verwandte Frage: Injizieren Sie einen EJB in JAX-RS (RESTful Service)

76
Andre Rodrigues

Wenn die Komponente ein EJB ist, sollte es kein Problem geben, eine EM zu injizieren.

Aber ... In JBoss 5 ist die JAX-RS-Integration nicht besonders gut. Wenn Sie über eine EJB verfügen, können Sie das Scannen nicht verwenden und müssen diese manuell in der Datei context-param resteasy.jndi.resource auflisten. Wenn Sie den Scanvorgang noch aktiviert haben, sucht Resteasy nach der Ressourcenklasse und registriert sie als Vanilla JAX-RS-Dienst. Anschließend wird der Lebenszyklus abgewickelt.

Das ist wahrscheinlich das Problem.

2
Bill Burke