2010-07-22 31 views
5

J'ai un service Web JAX-RS qui utilise des classes d'entités JPA. J'ai une classe de ressources comme ceci:Entité de groupage de threads NPE dans JAX-RS

@Path("/entity") 
public class MyEntityResource 
{ 
    @GET 
    @Produces(MediaType.APPLICATION_XML) 
    @Path("/{entity}") 
    public MyEntity getMyEntity(@PathParam("entity") String entity) 
    { 
     log.debug("Entering getMyEntity with param: " + entity); 
     MyEntity entityObject = genericService.find(MyEntity.class, entity); 

     if (entityObject == null) 
     { 
      log.debug("Entity not found."); 
      throw new WebApplicationException(Response.Status.NOT_FOUND); 
     } 

     log.debug("Exiting getMyEntity"); 

     return entityObject; 
    } 
} 

Quand je lance le service et faire un appel get sur l'entité, je reçois cette erreur:

SEVERE: The response of the WebApplicationException cannot be utilized as the response is already committed. Re-throwing to the HTTP container 
javax.ws.rs.WebApplicationException: javax.xml.bind.MarshalException 
- with linked exception: 
[Exception [EclipseLink-25003] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.XMLMarshalException 
Exception Description: An error occurred marshalling the object 
Internal Exception: java.lang.NullPointerException] 
    at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:151) 
... 
<snip> 
... 
Caused by: javax.xml.bind.MarshalException 
- with linked exception: 
[Exception [EclipseLink-25003] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.XMLMarshalException 
Exception Description: An error occurred marshalling the object 
Internal Exception: java.lang.NullPointerException] 
    at org.eclipse.persistence.jaxb.JAXBMarshaller.marshal(JAXBMarshaller.java:271) 
    at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:171) 
    at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:149) 
    ... 32 more 
Caused by: Exception [EclipseLink-25003] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.XMLMarshalException 
Exception Description: An error occurred marshalling the object 
Internal Exception: java.lang.NullPointerException 
    at org.eclipse.persistence.exceptions.XMLMarshalException.marshalException(XMLMarshalException.java:76) 
    at org.eclipse.persistence.oxm.XMLMarshaller.marshal(XMLMarshaller.java:502) 
    at org.eclipse.persistence.jaxb.JAXBMarshaller.marshal(JAXBMarshaller.java:269) 
    ... 34 more 
Caused by: java.lang.NullPointerException 
    at org.eclipse.persistence.exceptions.ConversionException.couldNotBeConverted(ConversionException.java:69) 
... 
<snip> 
... 
    at org.eclipse.persistence.oxm.XMLMarshaller.marshal(XMLMarshaller.java:916) 
    at org.eclipse.persistence.oxm.XMLMarshaller.marshal(XMLMarshaller.java:468) 
    ... 35 more 

Nulle part dans aucune des traces de la pile sont tout de mes classes référencées. En outre, l'instruction "Exiting getMyEntity" est enregistrée avant l'exception.

Je ne sais pas ce qui lance le NPE ou comment le déboguer.

Avant cette erreur, j'obtenais un [com.sun.istack.SAXException2: A cycle is detected in the object graph. This will cause infinitely deep XML: de mes classes d'entités JPA (EclipseLink) et j'ai ajouté l'annotation MOXy @XmlInverseReference à ma classe enfant sur la méthode getter parent.

Avez-vous des idées sur ce qui pourrait déclencher cette exception?

Répondre

4

Nous avons eu une discussion en ligne sur ce problème, et au profit des autres qui trouvent ce post ci-dessous est la configuration correcte de l'utilisation @XmlInverseReference à plusieurs niveaux:

Entité A

import java.io.Serializable; 
import javax.persistence.*; 
import javax.xml.bind.annotation.XmlAttribute; 
import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlRootElement; 

import java.util.Set; 

@Entity 
@XmlRootElement 
public class EntityA implements Serializable { 
    private static final long serialVersionUID = 1L; 
    private String name; 
    private Set<EntityB> entityBs; 

    @Id 
    @XmlAttribute 
    public String getName() { 
     return this.name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    @OneToMany(mappedBy = "entityABean") 
    @XmlElement 
    public Set<EntityB> getEntityBs() { 
     return this.entityBs; 
    } 

    public void setEntityBs(Set<EntityB> entityBs) { 
     this.entityBs = entityBs; 
    } 

} 

entité B

import java.io.Serializable; 
import javax.persistence.*; 
import javax.xml.bind.annotation.XmlAttribute; 
import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlRootElement; 

import org.eclipse.persistence.oxm.annotations.XmlInverseReference; 

import java.util.Set; 

@Entity 
@XmlRootElement 
public class EntityB implements Serializable { 
    private static final long serialVersionUID = 1L; 
    private String name; 
    private Set<EntityC> entityCs; 
    private EntityA entityABean; 

    @Id 
    @XmlAttribute 
    public String getName() { 
     return this.name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    @ManyToOne 
    @JoinColumn(name = "EntityA") 
    @XmlInverseReference(mappedBy = "entityBs") 
    public EntityA getEntityABean() { 
     return this.entityABean; 
    } 

    public void setEntityABean(EntityA entityABean) { 
     this.entityABean = entityABean; 
    } 

    @OneToMany(mappedBy = "entityBBean") 
    @XmlElement 
    public Set<EntityC> getEntityCs() { 
     return this.entityCs; 
    } 

    public void setEntityCs(Set<EntityC> entityCs) { 
     this.entityCs = entityCs; 
    } 
} 

Entité C

import java.io.Serializable; 
import javax.persistence.*; 

import org.eclipse.persistence.oxm.annotations.XmlInverseReference; 

@Entity 
public class EntityC implements Serializable { 
    private static final long serialVersionUID = 1L; 
    private String name; 
    private EntityB entityBBean; 

    @Id 
    public String getName() { 
     return this.name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    @ManyToOne 
    @JoinColumn(name = "EntityB") 
    @XmlInverseReference(mappedBy = "entityCs") 
    public EntityB getEntityBBean() { 
     return this.entityBBean; 
    } 

    public void setEntityBBean(EntityB entityBBean) { 
     this.entityBBean = entityBBean; 
    } 
} 

Démo

import java.io.FileInputStream; 
import javax.xml.bind.JAXBContext; 
import javax.xml.bind.Marshaller; 
import javax.xml.bind.Unmarshaller; 

public class Demo { 

    public static void main(String[] args) throws Exception { 
     JAXBContext jc = JAXBContext.newInstance(EntityA.class); 

     Unmarshaller unmarshaller = jc.createUnmarshaller(); 
     FileInputStream xml = new FileInputStream("src/test/jaxb/input.xml"); 
     EntityA a = (EntityA) unmarshaller.unmarshal(xml); 

     for(EntityB b : a.getEntityBs()) { 
      System.out.println(b.getEntityABean()); 
      for(EntityC c : b.getEntityCs()) { 
       System.out.println(c.getEntityBBean()); 
      } 
     } 
     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     marshaller.marshal(a, System.out); 
    } 

} 

Démo - Sortie

[email protected] 
[email protected] 
[email protected] 
[email protected] 
[email protected] 
[email protected] 

input.xml

<?xml version="1.0" encoding="UTF-8"?> 
<entityA> 
    <entityBs> 
     <entityCs/> 
     <entityCs/> 
    </entityBs> 
    <entityBs> 
     <entityCs/> 
     <entityCs/> 
    </entityBs> 
</entityA> 

Cette question est traitée aussi sur les forums EclipseLink, pour plus d'informations voir:

Ci-dessous est un autre exemple d'utilisation @XmlInverseReference avec un modèle JPA

+0

En plus de ce qui précède, le NPE a été provoqué par un champ Timestamp sur un classe/élément petit-enfant null. J'ai étendu XmlAdapter pour gérer le marshalling de Timestamps et cela a jeté le NPE. – sdoca

1

Avez-vous inclus un fichier jaxb.properties dans vos classes d'entités?

Découvrez la réponse de Blaise à cette question: JAXB Mapping cyclic references to XML

Hope this helps. RG

+0

De la trace de la pile, le fichier jaxb.properties semble être en place. –

+0

Merci de votre réponse. Oui, j'ai un jaxb.fichier de propriétés avec ce contenu: # Préciser que la mise en œuvre EclipseLink Moxy JAXB doit être utilisé javax.xml.bind.context.factory = org.eclipse.persistence.jaxb.JAXBContextFactory je crois qu'il est lu parce que la trace de la pile fait référence à: org.eclipse.persistence.jaxb.JAXBMarshaller.marshal (JAXBMarshaller.java:271) Je l'ai vu l'autre poste, qui est où j'appris Moxy et l'annotation @XmlInverseReference que je dans mon code . – sdoca