2010-07-22 4 views
5

Ho un servizio web JAX-RS che fa uso di classi di entità JPA. Ho una classe di risorse come questo:Entità di marshalling generata NPE in 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; 
    } 
} 

Quando eseguo il servizio e fare una chiamata get sull'entità, ottengo questo errore:

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 

Da nessuna parte in nessuna delle tracce dello stack sono qualsiasi delle mie classi di riferimento. Inoltre, l'istruzione "Exiting getMyEntity" viene registrata prima dell'eccezione.

Non ho idea di cosa stia lanciando l'NPE o di come eseguire il debug di questo.

Prima di questo errore, mi è stato sempre un [com.sun.istack.SAXException2: A cycle is detected in the object graph. This will cause infinitely deep XML: dai miei JPA (EclipseLink) classi di entità e ho aggiunto l'annotazione Moxy @XmlInverseReference alla mia classe figlia sul metodo genitore getter.

Qualche idea su cosa potrebbe essere questa eccezione?

risposta

4

Abbiamo avuto qualche discussione in linea su questo problema, e per il bene degli altri che trovano questo post qui sotto è la corretta impostazione di utilizzare @XmlInverseReference a più livelli:

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

Demo

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

} 

Demo - Uscita

[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> 

Questo problema è anche gestita sul forum EclipseLink, per maggiori informazioni vedi:

Qui di seguito è un altro esempio di utilizzo di @XmlInverseReference con un modello di JPA

+0

Oltre a quanto sopra, l'NPE è stato causato da un campo Timestamp su una classe/elemento di nipote che era null. Ho esteso XmlAdapter per gestire il marshalling di Timestamp e questo ha gettato l'NPE. – sdoca

1

Hai inserito un file jaxb.properties nelle tue classi di entità?

Partenza risposta di Blaise a questa domanda: JAXB Mapping cyclic references to XML

Spero che questo aiuti. RG

+0

Dalla traccia dello stack, il file jaxb.properties sembra essere a posto. –

+0

Grazie per la risposta. Sì, ho un jaxb.File delle proprietà di questi contenuti: # Specificare che l'attuazione EclipseLink moxy JAXB dovrebbe essere usato javax.xml.bind.context.factory = org.eclipse.persistence.jaxb.JAXBContextFactory Credo che sia in corso la lettura, perché l'analisi dello stack si riferisce a: org.eclipse.persistence.jaxb.JAXBMarshaller.marshal (JAXBMarshaller.java:271) ho fatto vedere l'altro post, che è dove ho imparato a conoscere Moxy e l'annotazione @XmlInverseReference che ho usato nel mio codice . – sdoca

Problemi correlati