简体   繁体   English

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

[英]JAXB @XmlElements, different types but same name?

I have an Animal class and an extension of Animal called AnimalExtension. 我有一个Animal类和Animal的扩展名为AnimalExtension。

public class Animal

public class AnimalExtension extends Animal

The only difference between the two classes is that AnimalExtension has another instance variable called animalId. 这两个类之间的唯一区别是AnimalExtension有另一个名为animalId的实例变量。 Animal does not have this instance variable. Animal没有此实例变量。

I also have my own data type that I want to marshal and unamarshal to XML. 我也有自己的数据类型,我想要编组和解组XML。 This data type is called AnimalList. 此数据类型称为AnimalList。 inside AnimalList, there is a list of Animals as an instance variable. 在AnimalList中,有一个动物列表作为实例变量。

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

animalList can contain both Animal and AnimalExtension. animalList可以包含Animal和AnimalExtension。 However, on the XML I dont want the element to be named as AnimalExtension; 但是,在XML上我不希望该元素被命名为AnimalExtension; I want them all to have element name of Animal. 我希望他们都拥有Animal的元素名称。 I only want the extra attribute to show up when JAXB knows that the Animal is actually an instance of AnimalExtension. 当JAXB知道Animal实际上是AnimalExtension的一个实例时,我只希望显示额外的属性。 So if I have a list of that looks like 所以,如果我有一个列表,看起来像

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

I want the XML to look like 我希望XML看起来像

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

This is what I have tried to do 这是我试图做的

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

The code compiles but when I try running my server. 代码编译但是当我尝试运行我的服务器时。 It gives me this weird error that is so unrelated to what is going on (BeanCreationException). 它给了我这个与正在发生的事情无关的奇怪错误(BeanCreationException)。 I tried making the name of the XmlElement to be different for each type and that works, but the challenge here is to make the name the same. 我尝试使XmlElement的名称对于每种类型都不同并且有效,但这里的挑战是使名称相同。

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

To map this use case you could leverage the following XmlAdapters: 要映射此用例,您可以利用以下XmlAdapter:

AnimalAdapter AnimalAdapter

Since AnimalExtension is a super set of Animal we will use it to produce/consume XML. 由于AnimalExtension是Animal的超级集合,我们将使用它来生成/使用XML。 Then we will leverage the value of the animalId property to determine if an instance of Animal or AnimalExtension will be returned to AnimalList. 然后我们将利用animalId属性的值来确定是否将Animal或AnimalExtension的实例返回到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 IdAdapter

We will need a second XmlAdapter to suppress animalId if its value is 0: 如果其值为0,我们将需要第二个XmlAdapter来抑制animalId:

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

}

Your model classes will be annotated as follows: 您的模型类将注释如下:

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

}

Demo Code 演示代码

The following demo code can be used to demonstrate this solution: 以下演示代码可用于演示此解决方案:

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

}

The following output will be produced: 将生成以下输出:

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>

Related Information 相关信息

You may find the following information useful: 您可能会发现以下信息有用:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM