2010-06-18 20 views
18

Tengo un gráfico de objetos que contiene un ciclo. ¿Cómo hago para que JAXB maneje esto? Intenté usar la anotación @XmlTransient en la clase secundaria, pero el contador de referencias JAXB todavía detecta el ciclo.JAXB Asignación de referencias cíclicas a XML

@Entity 
@XmlRootElement 
public class Contact { 

    @Id 
    private Long contactId; 

    @OneToMany(mappedBy = "contact") 
    private List<ContactAddress> addresses; 

... 

} 

@Entity 
@XmlRootElement 
public class ContactAddress { 

    @Id 
    private Long contactAddressId; 

    @ManyToOne 
    @JoinColumn(name = "contact_id") 
    private Contact contact; 

    private String address; 

... 

} 

Respuesta

12

Lo bueno de usar JAXB es que es un tiempo de ejecución estándar con múltiples implementaciones (como JPA).

Si utiliza EclipseLink JAXB (MOXy), tiene muchas extensiones disponibles para manejar entidades JPA, incluidas las relaciones bidireccionales. Esto se hace usando la anotación MOXy @XmlInverseReference. Actúa de forma similar a @XmlTransient en el Marshal y completa la relación de destino a origen en el unmarshal.

http://wiki.eclipse.org/EclipseLink/Examples/MOXy/JPA/Relationships

@Entity 
@XmlRootElement 
public class Contact { 

    @Id 
    private Long contactId; 

    @OneToMany(mappedBy = "contact") 
    private List<ContactAddress> addresses; 

... 

} 

@Entity 
@XmlRootElement 
public class ContactAddress { 

    @Id 
    private Long contactAddressId; 

    @ManyToOne 
    @JoinColumn(name = "contact_id") 
    @XmlInverseReference(mappedBy="addresses") 
    private Contact contact; 

    private String address; 

... 

} 

Otras extensiones están disponibles, incluyendo soporte para claves compuestas & clases clave incrustadas.

Para especificar la aplicación EcliseLink moxy JAXB es necesario incluir un archivo de jaxb.properties con las clases del modelo (es decir, contrato) con la siguiente entrada:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory 
+0

Quizás esto sea un problema JAX-RS. Aún recibo la excepción que indica que se detectó un ciclo - javax.ws.rs.WebApplicationException: javax.xml.bind.MarshalException - con excepción vinculada: [com.sun.istack.SAXException2: se detecta un ciclo en el gráfico de objetos . –

+0

Deberá agregar un archivo jaxb.properties que especifique el tiempo de ejecución de EclipseLink MOXy. He agregado las instrucciones a mi respuesta anterior. –

+0

Funciona muy bien. Gracias. –

17

This page en la "Guía JAXB no oficial" ofrece tres estrategias para hacer frente a los ciclos. Son (en resumen):

  • Marque uno de los atributos de referencia que forman el ciclo como @XmlTransient.
  • Utilice @XmlID y @XmlIDREF para que las referencias se representen utilizando identificadores XML a diferencia de la contención.
  • Utilice la interfaz CycleRecoverable para tratar los ciclos mediante programación.
+0

XmlID y XmlIDREF son fáciles de usar. Agregue la anotación XmlID a un método public String getId() {return Integer.toString (System.identityHashCode (this)); } y obtienes una forma simple de asignar identificadores únicos a tus elementos XML. – astraujums

6

XMLTransient casi siempre funciona para los ciclos. Es posible que tengas XMLTransient en el nivel de campo pero no hayas especificado que XMLAccessorType sea XmlAccessType.Field. Si no especifica nada, el valor predeterminado es XmlAccessType.Property, o sus getters. Experimenté que Jaxb seleccionaba elementos xml de getters de una clase en la que me perdía las anotaciones de tipo de acceso y todavía funcionaba perfectamente bien.

1

Podemos utilizar XStream biblioteca, así, yo lo probé un proyecto donde JAXB estaba dando error cíclico pero xstream manejado con éxito

+1

Es costumbre mostrar cómo usaría además de proporcionar la referencia. Por favor, edite su respuesta para incluir esto. –

Cuestiones relacionadas