Netbeans
has a handy feature off on the palette on the right (usually) of the code
editor, where you can drag a marshal or unmarshal object into your Java code and
it will generate marshal/unmarshal code for the XML or JAXB object of your
choice.
It is interesting that sometimes, although it does not complain when generating
these code fragments, there will occur an error at runtime stating that an
object has no @XmlRootElement.
@XmlRootElement annotations are not always created in JAXB objects. Here is a
nice explanation of why that is:
http://weblogs.java.net/blog/kohsuke/archive/2006/03/why_does_jaxb_p.html
The subject of this post is not why this happens, but rather how to deal with
these objects when you don't want to use inline complex types.
Here's a sample marshal method more or less as generated by the wizard of
Netbeans:
private String jaxbMarshalToString(MyType jaxbObj) throws
javax.xml.bind.JAXBException, java.io.IOException {
java.io.StringWriter sw = new java.io.StringWriter();
javax.xml.bind.JAXBContext jaxbCtx =
javax.xml.bind.JAXBContext.newInstance(jaxbObj.getClass().getPackage().getName());
javax.xml.bind.Marshaller marshaller = jaxbCtx.createMarshaller();
marshaller.setProperty(javax.xml.bind.Marshaller.JAXB_ENCODING, "UTF-8");
//NOI18N
marshaller.setProperty(javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT,
Boolean.TRUE);
marshaller.marshal(jaxbObj, sw);
sw.close();
return sw.toString();
}
Here is an unmarshal method for the same object:
private MyType jaxbUnmarshalFromString(String str) throws
javax.xml.bind.JAXBException
{
MsgQMessageType ret = null;
javax.xml.bind.JAXBContext jaxbCtx =
javax.xml.bind.JAXBContext.newInstance(MyType.class);
javax.xml.bind.Unmarshaller unmarshaller = jaxbCtx.createUnmarshaller();
ret = (MyType) unmarshaller.unmarshal(new java.io.StringReader(str));
//NOI18N
return ret;
}
This object has "Type" appended to its name. That is a sign that this is a
container rather than the JAXB representation of the XSD itself. These methods
fail at runtime because the object
jaxbObj includes no root annotation.
Here are these two methods changed so they work. In the first method, we create
a new JAXBElement (so it will have a
root element) and marshal that. In the second method, we unmarshal to a JAXBElement, and
return that object's getValue(), cast to our desired type. Also in the unmarshal
code, the context is created using getPackage().getName() rather than just the
class.
private String jaxbMarshalToString(MyType jaxbObj) throws
javax.xml.bind.JAXBException, java.io.IOException {
java.io.StringWriter sw = new java.io.StringWriter();
javax.xml.bind.JAXBContext jaxbCtx =
javax.xml.bind.JAXBContext.newInstance(jaxbObj.getClass().getPackage().getName());
javax.xml.bind.Marshaller marshaller = jaxbCtx.createMarshaller();
marshaller.setProperty(javax.xml.bind.Marshaller.JAXB_ENCODING, "UTF-8");
//NOI18N
marshaller.setProperty(javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT,
Boolean.TRUE);
marshaller.marshal(new JAXBElement(
new QName("http://www.namespace.com/schema/My", "My"),
MyType.class, jaxbObj), sw);
sw.close();
return sw.toString();
}
private MyType jaxbUnmarshalFromString(String str) throws
javax.xml.bind.JAXBException
{
JAXBElement ret = null;
javax.xml.bind.JAXBContext jaxbCtx =
javax.xml.bind.JAXBContext.newInstance(MyType.class.getPackage().getName());
javax.xml.bind.Unmarshaller unmarshaller = jaxbCtx.createUnmarshaller();
ret = (JAXBElement) unmarshaller.unmarshal(new java.io.StringReader(str));
//NOI18N
return (MyType)ret.getValue();
}