JAXB @XmlElements,不同类型但同名? [英] JAXB @XmlElements, different types but same name?

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

问题描述

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

 公共类Animal 

公共类AnimalExtension扩展Animal

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



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

  @XmlType(name = AnimalList)
公共类AnimalList {
private List< Animal> animalList;
....

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

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

动物动物=新动物();
animal.setName(迈克);
animalList.add(animalExtension);
animalList.add(动物);

我希望XML看起来像

 < AnimalList> 
< Animal name =Donid =1/>
< Animal name =Mike/>
< / AnimalList>

这是我试图做的事情



< pre class =lang-java prettyprint-override> @XmlElements(
{
@XmlElement(name =Animal,type = Animal.class),
@XmlElement(name =Animal,type = AnimalExtension.class)
}

public List< Animal> getEntries(){
return animalList;
}

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

  org.springframework.beans.factory.BeanCreationException:创建名为'encryptionPayloadContentProvider'的bean时出错'


解决方案

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



AnimalAdapter



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

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

公共类AnimalAdapter扩展XmlAdapter< AnimalExtension,Animal> {

@Override
public Animal unmarshal(AnimalExtension animalExtension)抛出异常{
if(0!= animalExtension.getAnimalId()){
return animalExtension;
}
动物动物=新动物();
animal.setName(animalExtension.getName());
返回动物;
}

@Override
public AnimalExtension marshal(Animal animal)抛出异常{
if(animal.getClass()== AnimalExtension.class){
返回(AnimalExtension)动物;
}
AnimalExtension animalExtension = new AnimalExtension();
animalExtension.setName(animal.getName());
返回animalExtension;
}

}

IdAdapter



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

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

公共类IdAdapter扩展XmlAdapter< String,Integer> {

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

@Override
public String marshal(整数整数)抛出异常{
if(integer == 0){
return null;
}
返回String.valueOf(整数);
}

}

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



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)
公共类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; 

公共类动物{

私人字符串名称;

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

公共类AnimalExtension扩展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 static void main(String [] args)throws Exception {
JAXBContext jc = JAXBContext.newInstance(AnimalList.class);

Unmarshaller unmarshaller = jc.createUnmarshaller();
文件xml =新文件(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.0encoding =UTF- 8\" >?;
< AnimalList xmlns:xsi =http://www.w3.org/2001/XMLSchema-instance>
< Animal name =Donid =1/>
< Animal name =Mike/>
< / AnimalList>

相关信息



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




I have an Animal class and an extension of Animal called 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. Animal does not have this instance variable.

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

I want the XML to look like

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

解决方案

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

AnimalAdapter

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

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:

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

}

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:

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

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆