How To Save Java Objects As XML

JAXB MarshalIntegration between disparate systems sometimes require a mapping exercise between the protocol XML and the POJO you are using for data storage processing. Java defines a comprehensive binding framework – JAXB –  which can be used for this task.

When the POJO matches the target XML more or less in structure, then JAXB is a possible solution fit. Coding-wise the requirements are minimal: there are 4 components that need to be catered for:

  • Schema & Namespace declarations: This normally occurs at the package level
  • XML Structure Definition: Root Element and Element/Attribute definitions
  • Marshal a POJO to XML (dependent on requirements)
  • Un-marshal XML to a POJO (dependent on requirements)

Schema & Namespace

This definition normally occurs at the package level. The assumption is that all data model POJO classes are located in the same package. The following is defined in the package-info.java file and applies to the entire package:

@XmlSchema(
namespace="", //can be defined, but the target system expects no localized namespace.
elementFormDefault = XmlNsForm.UNSET,
attributeFormDefault = XmlNsForm.UNSET,
xmlns = {
@XmlNs(prefix = "xsi", namespaceURI = "http://www.w3.org/2001/XMLSchema-instance"),
@XmlNs(prefix = "xsd", namespaceURI = "http://www.w3.org/2001/XMLSchema")
},
location = "http://www.w3.org/2001/XMLSchema")

Note that if the namespace element is set, then the resulting XML document’s namespace defaults to the package name. The abovementioned example is tailored to generate an XML structure that is compatible with Microsoft serialization.

XML Structure Definition

Each POJO class in the data model is annotated with the relevant JAXB annotations. We define only the top-level class here to simply the example.

The target XML must have the following structure:


<Request xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Organization/>
<Code/>
<Address/>
<Email/>
<Fax/>
<FeedbackEmail/>
<Home />
<Office />
<Mobile />
<Member>
<!-- The member structure is defined by its own POJO -->
</Member>
<Requirements>
<Requirement>
<!-- The requirement structure is defined by its own POJO -->
</Requirement>
</Requirements>
</Request>

The JAXB annotations on our POJO is intended to generate the abovementioned XML once marshaled. Consequently the un-marshaling process must produce the POJO from XML.

@XmlRootElement(name = "Request")
@XmlAccessorType(XmlAccessType.FIELD)
public class MyRequest implements Serializable {

@XmlElement(name = "Organization")
private String organization = "";
@XmlElement(name = "Code")
private String code = "";
@XmlElement(name = "Address")
private String address = "";
@XmlElement(name = "Email")
private String email = "";
@XmlElement(name = "Fax")
private String fax = "";
@XmlElement(name = "FeedbackEmail")
private String feedbackEmail = "";
@XmlElement(name = "Home")
private String home = "";
@XmlElement(name = "Office")
private String office = "";
@XmlElement(name = "Mobile")
private String mobile = "";

@XmlElement(name = "Member")
private MyMember member = new MyMember();

@XmlElement(name = "Requirement")
@XmlElementWrapper(name = "Requirements")
private List<SomeRequirement> requirements = new ArrayList<SomeRequirement>();

//...gettters and setters are not pertinent to this example

}

Marshal a POJO to XML

The following example illustrates how to marshal a POJO to an output stream. The example method also forces the target namespace if required.

public static <T extends Object> void marshal(T object, OutputStream os, String namespace) throws IOException {
try {
XmlRootElement anno = object.getClass().getAnnotation(XmlRootElement.class);
JAXBContext context = JAXBContext.newInstance(object.getClass());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
if (anno == null){
final QName qname = new QName(namespace, object.getClass().getSimpleName());
@SuppressWarnings("unchecked")
JAXBElement<T> element = new JAXBElement<T>(qname, (Class<T>) object.getClass(), object);
marshaller.marshal(element, os);
}else{
marshaller.marshal(object, os);
}
} catch (PropertyException e) {
throw new IOException("Unable to marshal object to XML outputstream.", e);
} catch (JAXBException e) {
throw new IOException("Unable to marshal object to XML outputstream.", e);
} finally {

}
}

 

Un-marshal XML to a POJO

The example method uses JAXB to un-marshal XML from an input stream to an arbitrary object type. The use of generics introduces a degree of reuse in code.

public static <T extends Object> T unmarshal(Class<T> cls, InputStream is) throws IOException {
try {
JAXBContext context = JAXBContext.newInstance(cls);
Unmarshaller unmarshaller = context.createUnmarshaller();
JAXBElement<T> root = unmarshaller.unmarshal(new StreamSource(is), cls);
T retval = root.getValue();
return retval;
} catch (JAXBException e) {
throw new IOException("Unable to unmarshal object from XML inputstream.", e);
} finally {
}
}

Posted in XML and tagged , .

Leave a Reply