Serializing with JAXB and the Any
Below I will demonstrate JAXB (JSR-222) and any
with an example:
Payload
The any
property is annotated with @XmlAnyElement(lax=true)
. This means that for that property if an element is associated with a class via @XmlRootElement
or @XmlElementDecl
then an instance of the corresponding object will be used to populate the property if not the element will be set as an instance of org.w3c.dom.Element
.
package forum13941747;
import java.util.List;
import javax.xml.bind.annotation.*;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Payload", propOrder = {
"any"
})
public class Payload {
@XmlAnyElement(lax = true)
protected List<Object> any;
}
Foo
Below is an example of a class annotated with @XmlRootElement
.
package forum13941747;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Foo {
}
Bar
Below is an example of a class without the @XmlRootElement
annotation. In this use case we will leverage the @XmlElementDecl
annotation on a factory class (usually called ObjectFactory
) annotated with @XmlRegistry
.
package forum13941747;
public class Bar {
}
ObjectFactory
Below is an example of specifying an @XmlElementDecl
annotation for the Bar
class.
package forum13941747;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
import javax.xml.namespace.QName;
@XmlRegistry
public class ObjectFactory {
@XmlElementDecl(name="bar")
public JAXBElement<Bar> createBar(Bar bar) {
return new JAXBElement<Bar>(new QName("bar"), Bar.class, bar);
}
}
input.xml
Below is the input document we'll use for this example. There are 3 elements that correspond to the any
property. The first corresponds to the @XmlRootElement
annotation on the Foo
class. The second corresponds to the @XmlElementDecl
annotation for the Bar
class and the third does not correspond to any of the domain classes.
<?xml version="1.0" encoding="UTF-8"?>
<payload>
<foo/>
<bar/>
<other/>
</payload>
Demo
In the demo code below we will unmarshal the input document, then output the classes of the objects in the resulting any
property and then marshal the payload
object back to XML.
package forum13941747;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Payload.class, Foo.class, ObjectFactory.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum13941747/input.xml");
Payload payload = (Payload) unmarshaller.unmarshal(xml);
for(Object o : payload.any) {
System.out.println(o.getClass());
}
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(payload, System.out);
}
}
Output
Below is the output from running the demo code. Note the classes corresponding to the objects in the any
property. The foo
element became an instance of the Foo
class. The bar
element became an instance of JAXBElement
that holds an instance of Bar
. The other
element became an instance of org.w3c.dom.Element
.
class forum13941747.Foo
class javax.xml.bind.JAXBElement
class com.sun.org.apache.xerces.internal.dom.ElementNSImpl
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<payload>
<foo/>
<bar/>
<other/>
</payload>
Make use of Object Factory for mashelling the object like below you no need to have @XmlRootElement in DemoType.java .,
DemoType demoServiceRequest = new DemoType();
ObjectFactory obDemo = new ObjectFactory();
Request requestObject = new Request();
requestObject.setAny(obDemo.createDemo(demoServiceRequest));
And add DemoType class at Request.java like @XmlSeeAlso({DemoType.class})