I have a hierarchy of JAXB-generated classes. I would like to marshal a child class as a base class element (but with all the child class attributes), using xsi:type to indicate the concrete type.
For example, given an Animal and a Bird subclass:
<xs:complexType name="animal" abstract="true">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="bird">
<xs:complexContent>
<xs:extension base="animal">
<xs:sequence>
<xs:element name="maxAltitude" type="xs:int"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="Animal" type="animal"/>
<xs:element name="Bird" type="bird"/>
No matter how I marshal a Bird, for example:
Bird sparrow = new Bird();
sparrow.setName("Sparrow");
sparrow.setMaxAltitude(1000);
JAXBContext context = JAXBContext.newInstance(Animal.class, Bird.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(sparrow, System.out);
The result is always a Bird element:
<Bird xmlns="http://mycompany.com/animals">
<name>Sparrow</name>
<maxAltitude>1000</maxAltitude>
</Bird>
However what I want is this (all attributes of subclass, xsi type, base class element name):
<Animal xmlns="http://mycompany.com/animals"
xsi:type="bird"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<name>Sparrow</name>
<maxAltitude>1000</maxAltitude>
</Animal>
What's odd is that if I create a wrapper element:
<xs:complexType name="animalWrapper">
<xs:sequence>
<xs:element name="Animal" type="animal"/>
</xs:sequence>
</xs:complexType>
<xs:element name="AnimalWrapper" type="animalWrapper"/>
and marshal it, it uses the base class type:
<AnimalWrapper xmlns="http://mycompany.com/animals"
<Animal xsi:type="bird"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<name>Sparrow</name>
<maxAltitude>1000</maxAltitude>
</Animal>
</AnimalWrapper>
If I manually build my desired XML document, JAXB has no problem unmarshalling it. How can I author my XML schema and/or configure JAXB to allow my desired marshalling behavior?
Thanks.
You could do the following:
QName qName = jc.createJAXBIntrospector().getElementName(new Animal());
JAXBElement<Animal> jaxbElement = new JAXBElement<Animal>(qName, Animal.class, new Bird());
marshaller.marshal(jaxbElement, System.out);
Check out:
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