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?
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group
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?
We did that on purpose to prevent the key from being repeated.
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.
This is how I would recommend solving your use case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With