Speed up XML programming with JAXB

February 24th, 2009 Jorge Balderas, Consultant

The Problem

As a software developer or architect, you have many options available for working with XML files within your application. Say, for example, you only need to use a small subset of fields from an XML document, then using a SAX (Simple API for XML) is a good solution. If you need to generate XML documents, a DOM (Document Object Model) API will be a natural choice. An XML schema allows you to define very complex structures and include different XML Schema namespaces (fully qualified XML type names). Writing code to read and manipulate these can be very cumbersome and become difficult to maintain with traditional XML parsers.

The Solution

Wouldn’t it be great if you could easily map your application classes to XML schemas and vice versa? Well, XML binding frameworks are meant to provide that capability. Specifically in the Java world, the “Java Architecture for XML Binding” (JAXB) is a specification (JSR 222) that allows mapping XML types to Java types. The JAXB Reference Implementation is a very powerful and comprehensive framework that allows binding Java objects to XML Schemas (XSDs) back and forth. It also provides tools to generate, at design time, a Java class that maps to an XML schema.

How does JAXB work?

To illustrate how JAXB is used for Java to XML binding I created a very simple XML Schema that contains a CodeMetric type:

<xs:element name="CodeMetric">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="moduleName" type="xs:string" />
      <xs:element name="estimateDays" type="xs:int" />
      <xs:element minOccurs="0" name="actualDays" type="xs:int" />
      <xs:element name="numberOfDevelopers" nillable="true"
                  type="xs:int" />
      <xs:element minOccurs="0" name="repeatable" nillable="true"
                  type="xs:boolean" />
      <xs:element name="complexity" type="ns1:ComplexityEnum" />
      <xs:element name="size">
      <xs:simpleType>
        <xs:restriction base="xs:string">
        <xs:enumeration value="small" />
        <xs:enumeration value="medium" />
        <xs:enumeration value="large" />
        </xs:restriction>
      </xs:simpleType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
</xs:element>
<xs:simpleType name="ComplexityEnum">
  <xs:restriction base="xs:string">
  <xs:enumeration value="easy" />
  <xs:enumeration value="intermediate" />
  <xs:enumeration value="hard" />
  </xs:restriction>
</xs:simpleType>

The first step is to generate corresponding Java classes for the schema above. The JAXB distribution includes a binding compiler: the xjc.bat tool. To generate the classes simply provide the xsd file name or the path to the folder containing xsd files as follows:

xjc.bat schema\*.xsd

The following annotated Java class will be generated:

public class CodeMetric {
  @XmlElement(required = true)
  protected String moduleName;

  protected int estimateDays;

  protected Integer actualDays;

  @XmlElement(required = true, type = Integer.class, nillable = true)
  protected Integer numberOfDevelopers;

  @XmlElementRef(name = "repeatable", type = JAXBElement.class)
  protected JAXBElement<Boolean> repeatable;

  @XmlElement(required = true)
  protected ComplexityEnum complexity;

  @XmlElement(required = true)
  protected String size;
}

In the schema above, note that the “complexity enumeration” is defined differently than the “size enumeration”. The “size enumeration” is defined inline, where as the “complexity enumeration” is defined as a named complex type. This was done intentionally to illustrate that JAXB will generate a Java enumeration class only for the enumerations that are named. This is the generated Java enumeration class for the ComplexityEnum XML type:

@XmlEnum
public enumComplexityEnum {
  @XmlEnumValue("easy")
  EASY("easy"), 

  @XmlEnumValue("intermediate")
  INTERMEDIATE("intermediate"),

  @XmlEnumValue("hard")
  HARD("hard");

  private final String value;

Next you will need to create code to unmarshall (turn an XML document into a Java object) and marshall (turn Java code into an XML document).  The key class to use is the JAXBContext. This class requires specifying the Java package names of the classes to be marshalled or unmarshalled. If there are multiple packages used, they can be separated using the ‘:’ character.

public CodeMetricsHandler() throws JAXBException {
  JAXBContext jc = JAXBContext.newInstance("com.summa.metrics");
  this.marshaller = jc.createMarshaller();
  this.unmarshaller = jc.createUnmarshaller();
}

For convenience you can create a method to unmarshall XML into a Java instance. In most cases the most convenient type to use is a string, but it can also be a file name for instance, or an input stream. The return type is the corresponding Java type. The method below will unmarshall a string which contains a valid CodeMetric XML document into a CodeMetric Java instance.

public CodeMetric unmarshallCodeMetric(String xmlString)
  throws JAXBException {
  CodeMetric cm = null;
  cm = (CodeMetric)this.unmarshaller.unmarshal(
  new StreamSource(new StringReader(xmlString)));
  return cm;
}

Similarly, you can create a method that will marshall a java object into an XML document.

public String marshallCodeMetric(CodeMetric update) throwsJAXBException {
  String xml = null;
  StringWriter writer = new StringWriter();
  this.marshaller.marshal(update, writer);
  xml = writer.toString();
  return xml;
}

What if the default binding does not work for me?

JAXB is a very powerful XML binding framework. The steps outlined above only touch on the basics of marshalling and unmarshalling. On a greenfield project, using the default bindings without any customizations may work, but in many cases existing XML schemas cannot be tweaked or existing Java types need to be reused.  You may also want to use a different java package than the one mapped from the schema. JAXB allows very granular customizations of the binding. This can be accomplished either through the use of XML annotations in the schema or specified through separate (.xjb) files.

Conclusion

JAXB and similar XML binding frameworks can significantly reduce development and testing time by abstracting a lot of the cumbersome details when dealing with XML schemas. It reduces the room for error and maintenance time. If the schema changes, the JAXB classes need to be regenerated. An IDE will quickly point out which types changed at compilation time. JAXB is not a “one size fits all” solution. If your project uses XML schemas and your application classes closely resemble the types defined in the schemas, JAXB is likely a good solution for your needs.

Share and Enjoy:
  • Digg
  • Reddit
  • del.icio.us
  • Google
  • description
  • LinkedIn

Entry Filed under: Software Development

5 Comments Add your own

  • 1. Handerson Gomes  |  March 2nd, 2009 at 5:07 pm

    I would like to add a reference to XStream (http://xstream.codehaus.org/) which is a plain library to serialize objects to XML and back again.

    It has some customizations options and is very simple to use. It can work well in some scenarios, for example, when the need is to create an XML version of a Java Object, instead of writing Java code to handle a pre-defined XML format.

    We have used XStream in a project to communicate with Flex using HTTP Services and it worked quite well.

  • 2. Jorge Balderas  |  March 2nd, 2009 at 9:25 pm

    Thanks for adding the reference to XStream, Handerson. It is an interesting and practical approach. I specially liked the annotations capability from XStream. It is good to know about it.

    I should mention that JAXB allows generating an XML Schema from Java classes using the schemagen plugin. Not quite as practical as XStream, but can be useful in some cases.

  • 3. das  |  June 28th, 2009 at 1:49 pm

    I want to create a custom getter method. I will explain.
    If the generated default getter method for String firstName is

    public String getFirstName(){
    return this.firstName;
    }

    I want something like

    public String getFirstName(){
    if(this.firstName==null){
    return new String(”xyz”);
    }
    }

    In case of custom objects, I need something like

    public MyObject getMyObject(){
    if(this.myObject==null){
    return new MyObject);
    }
    }

    How can I do this using JAXB when I generate the beans from XSD.
    Please help.

    -Das

  • 4. Jorge Balderas  |  June 30th, 2009 at 10:13 am

    Das - I’ve never done that particular customization. My recommendation is to check out class and property bindings. You may be able to accomplish this by overriding the binding to use your own “first name” property (get/set implementation)… hope this helps!

  • 5. 10 practical recommendati&hellip  |  November 10th, 2009 at 8:55 am

    [...] Even if you are an XML schema expert, an XML Schema editor can help you become more productive. From my experience, a good tool must meet three basic requirements. First, it must provide auto-complete capabilities and allow you to validate the schema. The second requirement is that it should let you generate sample XML files with various options, such as for populating optional nested elements up to N levels. Finally, it must let you validate an XML file against a set of schemas. This last functionality is essential during integration testing for validating files generated by applications that are not relying on an XML binding framework. [...]

Leave a Comment

Required

Required, hidden

Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Trackback this post  |  Subscribe to the comments via RSS Feed


Pages

Categories

Most Recent Posts

Feeds

  Subscribe in a reader

Calendar

February 2009
M T W T F S S
« Jan   Mar »
 1
2345678
9101112131415
16171819202122
232425262728  

Tags