JAXB @XmlElements,不同类型但同名?

我有一个Animal类和Animal的扩展名为AnimalExtension。

public class Animal public class AnimalExtension extends Animal 

这两个类之间的唯一区别是AnimalExtension有另一个名为animalId的实例变量。 Animal没有这个实例变量。

我也有自己的数据类型,我想编组和解组XML。 此数据类型称为AnimalList。 在AnimalList中,有一个动物列表作为实例变量。

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

animalList可以包含Animal和AnimalExtension。 但是,在XML上我不希望该元素被命名为AnimalExtension; 我希望他们都拥有Animal的元素名称。 当JAXB知道Animal实际上是AnimalExtension的一个实例时,我只希望显示额外的属性。 所以,如果我有一个列表,看起来像

 List animalList = new LinkedList(); AnimalExtension animalExtension = new AnimalExtension(); animalExtension.setAnimalId(1); amimalExtension.setName("Don"); Animal animal = new Animal(); animal.setName("Mike"); animalList.add(animalExtension); animalList.add(animal); 

我希望XML看起来像

     

这是我试图做的

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

代码编译但是当我尝试运行我的服务器时。 它给了我这个奇怪的错误,它与正在发生的事情(BeanCreationException)无关。 我尝试使XmlElement的名称对于每种类型都有所不同,但是这样做的挑战是使名称相同。

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

要映射此用例,您可以利用以下XmlAdapter:

AnimalAdapter

由于AnimalExtension是Animal的超级集合,我们将使用它来生成/使用XML。 然后我们将利用animalId属性的值来确定是否将Animal或AnimalExtension的实例返回到AnimalList。

 import javax.xml.bind.annotation.adapters.XmlAdapter; public class AnimalAdapter extends XmlAdapter { @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

如果其值为0,我们将需要第二个XmlAdapter来抑制animalId:

 import javax.xml.bind.annotation.adapters.XmlAdapter; public class IdAdapter extends XmlAdapter { @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); } } 

您的模型类将注释如下:

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 animalList = new ArrayList(); @XmlElement(name="Animal") @XmlJavaTypeAdapter(AnimalAdapter.class) public List getEntries() { return animalList; } } 

动物

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

演示代码

以下演示代码可用于演示此解决方案:

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

将生成以下输出:

 class AnimalExtension class Animal      

相关信息

您可能会发现以下信息有用: