2012-10-05 42 views
6

Estoy tratando de separar un documento XML de un sistema heredado usando JAXB. Tengo una estructura XML de la siguiente manera:JAXB desmaquillar con java generics

<response> 
    <id>000000</id> 
    <results> 
     <result> 
<!-- Request specific xml content --> 
      <year>2003</year> 
      <title>Lorem Ipsum</title> 
      <items> 
       <item>I1</item> 
       <item>I2</item> 
      </items> 
     </result> 
     <result> 
      <year>2007</year> 
      <title>Dolor sit amet</title> 
      <items> 
       <item>K1</item> 
       <item>K2</item> 
      </items> 
     </result> 
    </results> 
</response> 

Las etiquetas dentro de la parte especificada por <result> etiqueta cambiará dependiendo de mi solicitud. Dado que el contenido puede cambiar decidí utilizar genéricos para elementos de resultado y me he preparado mis Java Beans con anotaciones de la siguiente manera:

// imports here 
@XmlRootElement(name="response") 
@XmlAccessorType(XmlAccessType.FIELD) 
public class XResponse<T>{ 
    private String id; 

    @XmlElementWrapper(name="results") 
    @XmlElement(name="result") 
    private List<T> results; 

// setters and getters 
} 

... 

@XmlRootElement(name="result") 
@XmlAccessorType(XmlAccessType.FIELD) 
public class X1Result{ 
    private String year; 
    private String title; 
    @XmlElementWrapper(name="items") 
    @XmlElement(name="item") 
    private List<String> items; 

// setters and getters 
} 
... 

Traté unmarshalling el documento XML mediante el código de abajo:

JAXBContext context = JAXBContext.newInstance(XResponse.class, X1Result.class); 
Unmarshaller um = context.createUnmarshaller(); 
XResponse<X1Result> response = (XResponse<X1Result>) um.unmarshal(xmlContent); 

List<X1Result> results = unmarshal.getResults(); 
for (X1Result object : results) { 
    System.out.println(object.getClass()); 
} 

Tengo un problema durante el desemparejamiento que no puede convertir los elementos de la lista en la clase X1Result. En su lugar, usa org.apache.xerces.dom.ElementNSImpl.

¿Qué debo hacer para hacer que JAXB Unmarshaller use la clase X1Result?

Gracias de antemano

Respuesta

2

Creo que debería utilizar la herencia en lugar de los genéricos. Dado un XML como esto:

<?xml version="1.0" encoding="UTF-8"?> 
<response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <id>000000</id> 
    <results> 
     <result xsi:type="X1Result"> 
      <year>2003</year> 
      <title>Lorem Ipsum</title> 
      <items> 
       <item>I1</item> 
       <item>I2</item> 
      </items> 
     </result> 
     <result xsi:type="X1Result"> 
      <year>2007</year> 
      <title>Dolor sit amet</title> 
      <items> 
       <item>K1</item> 
       <item>K2</item> 
      </items> 
     </result> 
    </results> 
</response> 

Puede enlazar dinámicamente sus <result> entradas. Usted tiene un tipo de nivel superior:

@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(name = "XResult") 
@XmlSeeAlso({ 
    X1Result.class 
})public abstract class XResult { 

} 

Y tienes clases de ejecución:

@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(name = "X1Result") 
public class X1Result extends XResult { 
    @XmlElement(name = "year") 
    private String year; 

    @XmlElement(name = "title") 
    private String title; 

    @XmlElementWrapper(name = "items") 
    @XmlElement(name = "item") 
    private List<String> items; 
    ... 
} 

utilizar el tipo de nivel superior en su clase XResponse:

@XmlRootElement(name = "response") 
@XmlAccessorType(XmlAccessType.FIELD) 
public class XResponse { 
    @XmlElement(name = "id") 
    private String id; 

    @XmlElementWrapper(name = "results") 
    @XmlElement(name = "result") 
    private List<XResult> results; 
    ... 
} 

Y puede Resolver referencia utilizando el tipo de nivel superior:

context = JAXBContext.newInstance(XResponse.class, XResult.class); 
Unmarshaller unmarshaller = context.createUnmarshaller(); 
XResponse response = (XResponse) unmarshaller.unmarshal(new File("testfile.xml")); 

List<XResult> results = response.getResults(); 
for (XResult object : results) { 
    System.out.println(object.getClass()); 
} 
+0

El código anterior init ializes 'XResult' en lugar de' X1Result' y por lo tanto da error ya que es una clase abstracta. Además, el contenido del xml proviene de un sistema heredado y no hay información 'xsi: type' disponible. (aunque puedo agregarlo programáticamente) – Alper

+0

El código instanciará un 'X1Result' si el' xsi: type' está allí. Al menos, eso es lo que hace por mí. Buena suerte. – davidfmatheson

+0

Esto funcionó bien para mí sin el 'xsi: type' presente en el XML. Estoy usando Java 1.7.0_15. –