JAXB @XmlElements, разные типы, но одно и то же имя? - PullRequest
10 голосов
/ 15 февраля 2011

У меня есть класс Animal и расширение Animal под названием AnimalExtension.

public class Animal

public class AnimalExtension extends Animal

Единственное различие между этими двумя классами состоит в том, что AnimalExtension имеет другую переменную экземпляра с именем animalId. У Animal нет этой переменной экземпляра.

У меня также есть свой собственный тип данных, который я хочу маршалировать и деархивировать в XML. Этот тип данных называется AnimalList. внутри AnimalList есть список Animals как переменная экземпляра.

@XmlType(name = "AnimalList")
public class 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 animal = new Animal();
animal.setName("Mike");
animalList.add(animalExtension);
animalList.add(animal);

Я хочу, чтобы XML выглядел как

<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 было разным для каждого типа, и это работает, но задача здесь состоит в том, чтобы сделать имя одинаковым.

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

1 Ответ

10 голосов
/ 18 февраля 2011

Чтобы отобразить этот вариант использования, вы можете использовать следующие XmlAdapters:

AnimalAdapter

Поскольку AnimalExtension - это супер набор Animal, мы будем использовать его для производства / потребленияXML.Затем мы используем значение свойства 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

Нам понадобитсявторой XmlAdapter для подавления animalId, если его значение равно 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);
    }

}

Классы вашей модели будут аннотированы следующим образом:

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

}

Демонстрационный код

Следующеедемонстрационный код можно использовать для демонстрации этого решения:

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>

Связанная информация

Выможет оказаться полезной следующая информация:

...