I have a problem getting Moxy to generate "good" XML and JSON for a list of inherited objects. Either of the XML looks find or the JSON looks fine, but not at the same time. Here is the model:
public static abstract class Animal {
private String name;
protected Animal() {
}
protected Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@XmlRootElement
public static class Tiger extends Animal {
public Tiger() {
}
public Tiger(String name) {
super(name);
}
}
@XmlRootElement
public static class Lion extends Animal {
public Lion() {
}
public Lion(String name) {
super(name);
}
}
@XmlRootElement
public static class Zoo {
private List<Animal> animals = new ArrayList<>();
@XmlElementRef
public List<Animal> getAnimals() {
return animals;
}
public void setAnimals(List<Animal> animals) {
this.animals = animals;
}
public void addAnimal(Animal a) {
animals.add(a);
}
}
The XML and JSON generated from the following Zoo instance
zoo = new Zoo();
zoo.addAnimal(new Tiger("Hobbes"));
zoo.addAnimal(new Lion("Simba"));
zoo.addAnimal(new Tiger("Sherikan"));
Look like:
<?xml version="1.0" encoding="UTF-8"?>
<zoo>
<tiger>
<name>Hobbes</name>
</tiger>
<lion>
<name>Simba</name>
</lion>
<tiger>
<name>Sherikan</name>
</tiger>
</zoo>
{
"zoo" : {
"tiger" : [ {
"name" : "Hobbes"
}, {
"name" : "Sherikan"
} ],
"lion" : [ {
"name" : "Simba"
} ]
}
}
The XML looks exactly what I want it too, but the JSON is weird. The way that the Moxy uses the type as key does not preserve order among the elements in the list. Is this a bug or feature?
If I change the annotation on Zoo.animals
to @XmlElement
the JSON output looks fine, but the XML output has changed to something that I can't use.
{
"zoo" : {
"animals" : [ {
"type" : "tiger",
"name" : "Hobbes"
}, {
"type" : "lion",
"name" : "Simba"
}, {
"type" : "tiger",
"name" : "Sherikan"
} ]
}
}
<?xml version="1.0" encoding="UTF-8"?>
<zoo>
<animals xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="tiger">
<name>Hobbes</name>
</animals>
<animals xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="lion">
<name>Simba</name>
</animals>
<animals xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="tiger">
<name>Sherikan</name>
</animals>
</zoo>
The only way I've come up with to solve this is to create an external OXM binding file to override the annotation on Zoo.animals
. The binding below is registered using the property of JAXBContextProperties.OXM_METADATA_SOURCE.
<?xml version="1.0"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xml-accessor-type="PUBLIC_MEMBER" xml-accessor-order="ALPHABETICAL"
xml-mapping-metadata-complete="false"
package-name="com.example">
<java-types>
<java-type name="com.example.JAXBTest2$Zoo">
<java-attributes>
<xml-element java-attribute="animals"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Is there a better solution to this that doesn't use an external binding file?