2011-02-15 49 views
8

Tengo una clase de Animal y una extensión de Animal llamada AnimalExtension.JAXB @XmlElements, diferentes tipos pero el mismo nombre?

public class Animal 

public class AnimalExtension extends Animal 

La única diferencia entre las dos clases es que AnimalExtension tiene otra variable de instancia llamada animalId. Animal no tiene esta variable de instancia.

También tengo mi propio tipo de datos que quiero agrupar y unamarshal a XML. Este tipo de datos se llama AnimalList. dentro de AnimalList, hay una lista de Animales como una variable de instancia.

@XmlType(name = "AnimalList") 
public class AnimalList{ 
    private List<Animal> animalList; 
    .... 

animalList puede contener tanto Animal como AnimalExtension. Sin embargo, en XML no quiero que el elemento se denomine AnimalExtension; Quiero que todos tengan el nombre del elemento Animal. Solo quiero que aparezca el atributo extra cuando JAXB sepa que Animal es en realidad una instancia de AnimalExtension. Así que si tengo una lista de que se parece a

List<Animal> animalList = new LinkedList<Animal>(); 
AnimalExtension animalExtension = new AnimalExtension(); 
animalExtension.setAnimalId(1); 
amimalExtension.setName("Don"); 

Animal animal = new Animal(); 
animal.setName("Mike"); 
animalList.add(animalExtension); 
animalList.add(animal); 

Quiero que el XML para que parezca

<AnimalList> 
    <Animal name="Don" id="1" /> 
    <Animal name="Mike" /> 
</AnimalList> 

Esto es lo que he tratado de hacer

@XmlElements(
    { 
      @XmlElement(name = "Animal", type = Animal.class), 
      @XmlElement(name = "Animal", type = AnimalExtension.class) 
     } 
    ) 
    public List<Animal> getEntries() { 
     return animalList; 
    } 

El código se compila pero cuando intento ejecutar mi servidor Me da este extraño error que no está relacionado con lo que está sucediendo (BeanCreationException). Intenté hacer que el nombre de XmlElement fuera diferente para cada tipo y eso funciona, pero el desafío aquí es hacer que el nombre sea el mismo.

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'encryptionPayloadContentProvider' 
+5

Dado un XML cómo se supone que JAXB para determinar qué clase que se utiliza para la creación de objetos de Java? ¿Es la existencia del atributo 'id'? ¿Qué pasa si hay otra clase llamada 'AnimalEnhacement' con el atributo id? –

+0

buen punto lol. no pensé en eso. – denniss

Respuesta

9

Para asignar este caso de uso se podría aprovechar los siguientes XmlAdapters:

AnimalAdapter

Desde AnimalExtension es un súper conjunto de Animal lo vamos a utilizar para producir/consumir XML. Entonces aprovecharemos el valor de la propiedad animalId para determinar si una instancia de Animal o AnimalExtension será devuelta a AnimalList.

import javax.xml.bind.annotation.adapters.XmlAdapter; 

public class AnimalAdapter extends XmlAdapter<AnimalExtension, Animal> { 

    @Override 
    public Animal unmarshal(AnimalExtension animalExtension) throws Exception { 
     if(0 != animalExtension.getAnimalId()) { 
      return animalExtension; 
     } 
     Animal animal = new Animal(); 
     animal.setName(animalExtension.getName()); 
     return animal; 
    } 

    @Override 
    public AnimalExtension marshal(Animal animal) throws Exception { 
     if(animal.getClass() == AnimalExtension.class) { 
      return (AnimalExtension) animal; 
     } 
     AnimalExtension animalExtension = new AnimalExtension(); 
     animalExtension.setName(animal.getName()); 
     return animalExtension; 
    } 

} 

IdAdapter

Vamos a necesitar una segunda XmlAdapter para suprimir animalId si su valor es 0:

import javax.xml.bind.annotation.adapters.XmlAdapter; 

public class IdAdapter extends XmlAdapter<String, Integer> { 

    @Override 
    public Integer unmarshal(String string) throws Exception { 
     return Integer.valueOf(string); 
    } 

    @Override 
    public String marshal(Integer integer) throws Exception { 
     if(integer == 0) { 
      return null; 
     } 
     return String.valueOf(integer); 
    } 

} 

las clases del modelo serán anotados como sigue:

AnimalList

import java.util.ArrayList; 
import java.util.List; 

import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlRootElement; 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 

@XmlRootElement(name="AnimalList") 
public class AnimalList { 

    private List<Animal> animalList = new ArrayList<Animal>(); 

    @XmlElement(name="Animal") 
    @XmlJavaTypeAdapter(AnimalAdapter.class) 
    public List<Animal> getEntries() { 
     return animalList; 
    } 

} 

Animal

import javax.xml.bind.annotation.XmlAttribute; 

public class Animal { 

    private String name; 

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

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

} 

AnimalExtension

import javax.xml.bind.annotation.XmlAttribute; 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 

public class AnimalExtension extends Animal { 

    private int animalId; 

    @XmlAttribute(name="id") 
    @XmlJavaTypeAdapter(IdAdapter.class) 
    public int getAnimalId() { 
     return animalId; 
    } 

    public void setAnimalId(int animalId) { 
     this.animalId = animalId; 
    } 

} 

Código demostración

El siguiente código de demostración se puede utilizar para demostrar esta solución:

import java.io.File; 
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(AnimalList.class); 

     Unmarshaller unmarshaller = jc.createUnmarshaller(); 
     File xml = new File("input.xml"); 
     AnimalList animalList = (AnimalList) unmarshaller.unmarshal(xml); 

     for(Animal animal : animalList.getEntries()) { 
      System.out.println(animal.getClass()); 
     } 

     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     marshaller.marshal(animalList, System.out); 
    } 

} 

La siguiente salida se producirá:

class AnimalExtension 
class Animal 
<?xml version="1.0" encoding="UTF-8"?> 
<AnimalList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <Animal name="Don" id="1"/> 
    <Animal name="Mike"/> 
</AnimalList> 

Información relacionada

Usted puede encontrar la siguiente información útil:

Cuestiones relacionadas