I have an application doing XML<->conversions using Jaxb and automatically generated classes with maven-jaxb2-plugin.
Someplace deep in my schema, I have the possibility to enter “ANY” xml.
Update: this better describes my schema. Some known XML wrapping a totally unknown part (the “any” part).
<xs:complexType name="MessageType">
<xs:sequence>
<xs:element name="XmlAnyPayload" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:any namespace="##any"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="OtherElements">
....
</xs:sequence>
This maps (by jaxb) to a inner class like this.
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"any"
})
public static class XmlAnyPayload {
@XmlAnyElement(lax = true)
protected Object any;
When I unmarshall the entire structure, it is no problem. The “Object any” will render into a org.apache.xerces.dom.ElementNSImpl. Now, I want to recreate the Java object manually and then go to XML. How do I take some random XML and put into the any (org.apache.xerces.dom.ElementNSImpl) element to be able to build up the Java object?
Also, the next case is when I have this element as java, I want to unmarshall this very part (to be able to extract the XML string of this element). But this is not possible. I get an exception about root elements. But it is not possible to annotate ElementNSImpl.
unable to marshal type "com.sun.org.apache.xerces.internal.dom.ElementNSImpl" as an element because it is missing an @XmlRootElement annotation
Do you have any suggestions on how to handle these problems?
@XmlAnyElement(lax = true)means in plain English something like:This is exactly what is happening in your case. So if you want to actually unmarshal the content of this lax any, provide JAXB context with a mapping for the element you wish to unmarshal. The easiest way to do this is to annotate your class with
@XmlRootElementNow when you create your JAXB context, add
MyClassinto it:In this case, if JAXB meets the
{urn:bar}fooelement in the place of thatxs:any, it will know that this element is mapped ontoMyClassand will try to unmarshal MyClass.If you are creating JAXB context based on the package name (you probably do), you can still add you class (say,
com.acme.foo.MyClass) to it. The easiest way is to create acom/acme/foo/jaxb.indexresource:And the add your package name to the context path:
There are other ways with
ObjectFactoryetc., but the trick withjaxb.indexis probably the easiest one.Alternatively, instead of unmarshalling everything in one run, you can leave the content of
xs:anyas DOM and unmarshal it into the target object in a second unmarshalling with anothe JAXB context (which know yourMyClassclass). Something like:This approach is sometimes better, especially when you have a combination of container/payload schemas which are relatively independent. Depends on the case.
All said above applies to marshalling as well. It’s all neatly bidirectional.