本文介绍了JAXB @XmlElements,不同类型但同名?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an Animal class and an extension of Animal called AnimalExtension.

public class Animal

public class AnimalExtension extends Animal

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

The only difference between the two classes is that AnimalExtension has another instance variable called animalId. Animal does not have this instance variable.

我也有自己的数据类型,我想将其编组和解组为 XML.这种数据类型称为 AnimalList.在AnimalList里面,有一个Animals列表作为实例变量.

I also have my own data type that I want to marshal and unamarshal to XML. This data type is called AnimalList. inside AnimalList, there is a list of Animals as an instance variable.

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

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

animalList can contain both Animal and AnimalExtension. However, on the XML I dont want the element to be named as AnimalExtension; I want them all to have element name of Animal. I only want the extra attribute to show up when JAXB knows that the Animal is actually an instance of 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);

我希望 XML 看起来像

I want the XML to look like

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

这就是我尝试做的

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

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

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

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

推荐答案

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

To map this use case you could leverage the following XmlAdapters:

动物适配器

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

Since AnimalExtension is a super set of Animal we will use it to produce/consume 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.

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

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

We will need a second XmlAdapter to suppress animalId if its value is 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);
    }

}

您的模型类将被注释如下:

Your model classes will be annotated as follows:

动物列表

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

}

动物

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

}

演示代码

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

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

}

将产生以下输出:

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>

相关信息

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

You may find the following information useful:

这篇关于JAXB @XmlElements,不同类型但同名?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-23 20:02