July 3, 2011, 5:56 p.m.
posted by factorial
Data Binding Basics
Before getting into the specifics of JAXB, it will be helpful to take a look at the concepts that underlie data binding in general. Fundamentally, data binding is similar to the document object model APIs we've discussedDOM, JDOM, and dom4jin that it defines an association, referred to as a binding, between an XML document and a tree of Java objects. A tree of Java objects can be created from an XML document and vice versa. The difference is that when data binding, the Java objects mapped to the document are instances not of generic interfaces representing elements and attributes (and comments, processing instructions, etc.), but of specific classes that have a meaning beyond the XML document. In part to indicate this difference, with data binding you don't "parse" or "serialize" documents. Instead, you marshall XML into Java objects and unmarshall Java objects into an XML document. The components that sit between objects and XML documents are called marshallers and unmarshallers. This relationship is shown in Figure.
Marshallers and unmarshallers
Let's take a look at what we can do with a fictional data binding framework and the XML document in Figure.
A person XML document
Using DOM, outputting the first name looks something like:
DocumentBuilder documentBuilder = DocumentBuilderFactory.newDocumentBuilder( ); Document doc = documentBuilder.parse(new File("lola.xml")); Element element = doc.getDocumentElement( ); NodeList firstNames = element.getElementsByTagName("firstName"); Element firstName = (Element) firstName.item(0); System.out.println(firstName.getTextContent( ));
With a data binding framework, we can write much simpler code, as in Figure.
Unmarshalling to a Person object
This has both fewer lines of code and is much more obvious about what it is doing. The first line uses a factory class in our fictional framework to obtain a new instance of the Unmarshaller interface for this framework. The second line passes a File object for our document to the unmarshaller and returns an instance the Person class. Finally, we call the getFirstName( ) method on this object and output the result to the console.
Marshalling a Person object
The code above should raise a question: how did the unmarshaller in Figure know to create a Person object? And how did the marshaller in Figure know to create that specific XML structure and not, for example:
<person xmlns="http://www.example.com/person" firstName="Lola" lastName="Arbuckle"/>
// for the unmarshaller unmarshaller.addMapping(Person.class, "http://www.example.com/person", "person"); // for the marshaller marshaller.addMapping(Person.class, "http://www.example.com/person", "person"); marshaller.setMarshalPropertiesAsElements(Person.class, true);
This is reasonable, and Java's reflection features are good enough that you could write a simple data binding framework using this sort of configuration scheme. However, the more prevalent technique among current data binding frameworks is to put the configuration of the document-to-object mapping in some sort of class-level metadata, as seen in Figure.
Class metadata determines structure
In some frameworks, this metadata is located within the class definition itself, either through static methods and fields or Java annotations. In others, the metadata is contained in an external mapping configuration file (it should come as no surprise that this file is usually XML itself). Some frameworks support multiple configuration methods or combinations of methods.
Data Binding and Schemas
The above description of data binding left out a critical component: a schema. In many applications, the XML documents produced by a marshaller and consumed by an unmarshaller are expected to conform to a schema, whether that be a DTD, an XML Schema, a RELAX NG schema, or some other schema language. For data binding, schemas are used in two distinct ways. The first is that they can be used to validate the result of a marshalling or the input for unmarshalling, as shown in Figure.
Documents conform to a schema
The second area is that many data binding frameworks support generating the Java classes from a schema. This is usually referred to as compiling a schema and the application that performs it is called a schema compiler. In general, the compiler will have some mechanism for customizing the generated classes.
In addition to generating Java classes from a schema, a few frameworks, including JAXB 2.0, allow for the reverse: a schema definition can be generated from Java classes as seen in Figure.
JAXB 2.0 includes schema generation
When to (and When Not to) Use Data Binding
Data binding is designed to allow applications to easily move data between a set of Java classes and an XML representation where both the Java classes and the XML representation are defined in some way. When this is the case, data binding can be very useful and, as we've seen, produce significantly more readable source code. However, if you use data binding when it is not appropriate, you may find yourself spending more time combating the API. Here are some basic guidelines: