No @XmlRootElement generated by JAXB
To tie together what others have already stated or hinted at, the rules by which JAXB XJC decides whether or not to put the @XmlRootElement
annotation on a generated class are non trivial (see this article).
@XmlRootElement
exists because the JAXB runtime requires certain information in order to marshal/unmarshal a given object, specifically the XML element name and namespace. You can't just pass any old object to the Marshaller. @XmlRootElement
provides this information.
The annotation is just a convenience, however - JAXB does not require it. The alternative to is to use JAXBElement
wrapper objects, which provide the same information as @XmlRootElement
, but in the form of an object, rather than an annotation.
However, JAXBElement
objects are awkward to construct, since you need to know the XML element name and namespace, which business logic usually doesn't.
Thankfully, when XJC generates a class model, it also generates a class called ObjectFactory
. This is partly there for backwards compatibility with JAXB v1, but it's also there as a place for XJC to put generated factory methods which create JAXBElement
wrappers around your own objects. It handles the XML name and namespace for you, so you don't need to worry about it. You just need to look through the ObjectFactory
methods (and for large schema, there can be hundreds of them) to find the one you need.
@XmlRootElement is not needed for unmarshalling - if one uses the 2 parameter form of Unmarshaller#unmarshall.
So, if instead of doing:
UserType user = (UserType) unmarshaller.unmarshal(new StringReader(responseString));
one should do:
JAXBElement<UserType> userElement = unmarshaller.unmarshal(someSource, UserType.class);
UserType user = userElement.getValue();
The latter code will not require @XmlRootElement annotation at UserType class level.
This is mentioned at the bottom of the blog post already linked above but this works like a treat for me:
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(new JAXBElement<MyClass>(new QName("uri","local"), MyClass.class, myClassInstance), System.out);
As hinted at in one of the above answers, you won't get an XMLRootElement on your root element if in the XSD its type is defined as a named type, since that named type could be used elsewhere in your XSD. Try mking it an anonymous type, i.e. instead of:
<xsd:element name="myRootElement" type="MyRootElementType" />
<xsd:complexType name="MyRootElementType">
...
</xsd:complexType>
you would have:
<xsd:element name="myRootElement">
<xsd:complexType>
...
<xsd:complexType>
</xsd:element>