IBM Skip to main content
Search for:   within 
      Search help  
     IBM home  |  Products & services  |  Support & downloads   |  My account

developerWorks > XML | Java technology
developerWorks
XML and Java technologies: Data binding Part 3: JiBX architecture
88KBe-mail it!
Contents:
Pulling for performance
Staying in context
Java-centric versus XML-centric
Reflecting on performance
Enhancing class files
Defining bindings
Structure mapping
Conclusions
Resources
About the author
Rate this article
Related content:
Data binding, part 1
Data binding, part 2
Data binding with Castor
XML document model performance in Java
Understanding SAX
Understanding DOM
Subscriptions:
dW newsletters
dW Subscription
(CDs and downloads)
Tests in Part 2 showed JiBX delivers great performance -- here's how!

Level: Intermediate

Dennis M. Sosnoski (mailto:dms@sosnoski.com?cc=&subject=Data binding Part 3: JiBX architecture)
President, Sosnoski Software Solutions, Inc.
1 April 2003

Enterprise Java technology expert Dennis Sosnoski gives a guided tour of his JiBX framework for XML data binding in Java applications. After introducing the current frameworks in Part 1 and comparing performance in Part 2, he now delves into the details of the JiBX design that led to both great performance and extreme flexibility for mapping between XML and Java objects. How does JiBX do it? The keys are in the internal structure...

Part 1 of this series gives background on why you'd want to use data binding for XML, along with an overview of the available Java frameworks for data binding. Part 2 shows the performance of several frameworks on some sample documents. Here in Part 3 you'll find out the details of the new JiBX framework that delivers such great test scores. I'll start by recapping some basics from the introduction to JiBX in Part 2.

JiBX originated as my experiment to explore the performance limits of XML data binding in Java technology. As it progressed beyond the experimental stage, I decided to also make it a test bed for trying out what I call a Java-centric approach to data binding -- as opposed to the XML-centric approach used in generating an object model from an XML grammar. Because of these choices, JiBX deliberately differs from the established data binding frameworks in several respects.

At the core of these differences is the parsing technology that's used when unmarshalling documents. The established frameworks are all based on the widely used SAX2 push parser API. JiBX instead uses a newer pull parser API that provides a more natural interface for dealing with the sequence of elements in a document. Because of this different API, JiBX is able to use relatively simple code to handle unmarshalling.

This simpler unmarshalling code is the basis for the second major difference between JiBX and the other frameworks. The other frameworks either generate their own data classes -- which you're then required to use in your application -- or use a technique called reflection that provides runtime access to data indirectly, using the class information known to the Java Virtual Machine (JVM). JiBX instead uses code that it adds to your existing classes, working directly with the binary class files generated by a Java compiler. This gives the speed of direct access to data while keeping the flexibility of working with classes that you control.

The third JiBX difference goes along with this use of your existing classes. JiBX reads a binding definition file to control how the code it adds to your classes converts instances to and from XML. JiBX isn't the only data binding framework that supports this type of approach -- Castor, for one, also handles this -- but JiBX goes further than the alternatives in allowing you to change the relationship between your classes and the XML document.

I'll give details on each of these points in the remainder of this article. Even if you're planning to use an alternative framework for your projects, you'll find some solid food for thought in going through this description of JiBX.

Pulling for performance
The biggest single difference between JiBX and the other data binding frameworks is in how they handle an input XML document. Most XML parsers for the Java language implement the SAX2 API for use by the application program. This API has been refined over a period of years and is supported by many different parser implementations, including the most fully-featured parsers available today.

Data binding dictionary
Here's a mini-dictionary of some terms I'll use in this article:

Marshalling is the process of generating an XML representation for an object in memory, potentially including objects linked from the original object.

Unmarshalling is the reverse process of marshalling, building an object (and potentially a graph of linked objects) in memory from an XML representation.

Mapping is the set of rules used for the marshalling and unmarshalling of objects to and from XML documents. Data binding approaches using code generation from a grammar normally have implicit mappings built into the constructed objects, but JiBX (along with a few other frameworks) instead uses an explicit binding definition to control the mapping.

Grammar is a set of rules defining the structure of a family of XML documents. One type of grammar is the Document Type Definition (DTD) format defined by the XML specification, another increasingly common one is the W3C XML Schema (Schema) format.

Despite it's widespread usage, the SAX2 API has some serious drawbacks for many types of XML processing. These result from the style of interface implemented by SAX2 -- a push parsing approach. In push parsing, you define methods within your code that implement interfaces defined by the parser API. You then pass these methods (in the form of a handler) to the parser, along with a document to be parsed. The parser goes through the text of the document and interprets it according to XML rules, calling your handler methods to report the document components (elements, character data content, and so forth.) as it finds them in the text. Once the parser has completely processed the input document, it returns control back to your application -- but in the meantime the parser is in control.

The problem with this approach is that it requires your handler code to always know where the parser is in the document, and to interpret the components appropriately. At the most basic level, an element containing a simple text value is reported as three (or more) separate components: first the start tag, then the text (which may be in multiple pieces), and finally the end tag. Your handler generally needs to accumulate text until the end tag is reported, and then do something with the text. The "something" it does may be affected by other items, such as the attributes of the start tag, so that's more information that needs to be held. The net result is that handler code for push parsing tends to involve a lot of String matching on element names in chained if statements (or the equivalent using a java.util.Hashtable). This is messy to write and messy to maintain, not to mention inefficient.

Pull parsing turns parse event reporting around. Instead of the parser calling methods in your handler to report document components, you call the parser to get each component in turn -- the parser becomes essentially an iterator for moving through the components of a document. When you write code using this approach, the state information is actually inherent in the code. Take the case of an element that contains text: You can write your code with the knowledge that the element you're processing has text content, and just process it directly -- effectively one call to get the start tag, one call to get the content, and a third to get the end tag.

Better yet, you can write a method that handles any element that contains a text value -- just call the method with the expected element name, and it can return the text content (or an error, if the expected element is missing). This is especially convenient for building objects from XML (which is what unmarshalling is all about). Most XML documents use fixed ordering of child elements, so processing the children of a particular element becomes as simple as just making one call after another to this method. This is both simpler and faster than a SAX2-style handler approach.

Staying in context
JiBX extensively uses this technique of combining multiple parser operations in a single method. It wraps an internal pull parser interface in an unmarshalling context class that defines a variety of element and attribute access methods. These methods handle both parsing and data conversions to primitive types, along with specialized types of operations such as tracking objects with unique identifiers. Here are some examples of these methods:

  • parsePastStartTag(ns, name) -- Parses past the start of element, which must be the next parse component seen other than character data. Leaves the parse positioned following the start tag.
  • attributeText(ns, name) -- Gets text value of required attribute from current start tag.
  • attributeInt(ns, name, dflt) -- Gets int value of optional attribute from current start tag (returning default value if attribute is not present).
  • parseContentText(ns, name) -- Parses past the end of the current element, which must have only character data content. Returns the content.
  • parseElementText(ns, name) -- Parses the next element, which must have only character data content. Returns the content.

Wrapping the parser within an unmarshalling context allows a wide variety of access methods to be defined with a minimum of code. It also provides isolation from the actual parser being used. Because of this, the generated code that gets added to your classes is not specific to a particular parser, or even to a particular type of parser. This may be an important concern for the future. Right now the unmarshalling context is coded to use a parser that implements the XMLPull interface, an informal standard defined by some of the leading developers in the area of pull parsing. In the future, there's likely to be a Java technology standard for pull parsers. When that standard becomes available, JiBX will be able to use the standard with only minor changes to the unmarshalling context code.

JiBX uses a second type of context, the marshalling context, for writing an XML document when marshalling. Just as the unmarshalling context wraps the parser and provides a variety of specialized convenience methods for unmarshalling, the marshalling context wraps an output stream and provides its own set of convenience methods. These methods provide a component-at-a-time interface for constructing the output document. Here's a simplified list of basic methods:

  • startTag(nsi, name) -- Generates start tag without attributes.
  • startTagAttributes(nsi, name) -- Generates start tag with attributes to be added.
  • attribute(nsi, name, value) -- Adds attribute to current start tag (value may be String or primitive type).
  • closeStartEmpty() -- Closes start tag with no content (empty element).
  • closeStartContent() -- Closes start tag with content to follow.
  • textContent(value) -- Adds character data content to current element (String or primitive).
  • endTag(nsi, name) -- Generates end tag for element.

This interface for generating XML is simpler than those used by many other frameworks. It's designed primarily for use by code that's added by the JiBX framework rather than written by hand, so it avoids state checks and similar safeguards. It does properly handle escaping special characters as entities in text, but other than that it's up to the calling program to use the interface properly.

In the form shown here, this interface works with namespace indices. The marshalling context keeps an internal array of prefixes for namespaces, so looking up the prefix when generating output is just a matter of indexing into this array (as opposed to requiring a mapping operation, which would be needed if actual namespace URIs were passed). This approach is a compromise that simplifies handling without throwing away flexibility. An earlier version of the interface required static construction of qualified names (including a namespace prefix, if needed) for elements and attributes. This worked well for generating text output, but would have been difficult to convert to other forms of output (such as a parse event stream for building a DOM representation of the document).The newer form of the interface makes conversion much easier.

Java-centric versus XML-centric
Most of the data binding frameworks for Java language programs are focused on code generation from W3C XML Schema grammars. Using this approach, you start with a Schema grammar for the documents to be processed, then use a program that's part of the data binding framework to generate the Java language source code for a set of classes (the object model) that correspond to the Schema. This works well for many applications, especially those where the Schema grammars are defined in advance and not subject to change during the course of the project. For these types of applications, the object model constructed from a Schema can provide a very fast way to start working with documents.

The main drawback to the generated object model approach is that it ties your code directly to the structure of the XML document. Because of this, I call it an XML-centric approach. With a generated object model, your application code is forced to use an interface that reflects the XML structure rather than the structure the application may want to impose on the data in a document. This means there's no isolation between the XML and your application -- if the XML document structure (the Schema) changes in any significant respect, you'll need to regenerate the object model and change your application code to match.

A few data binding frameworks (including JiBX) have implemented an alternative approach, generally called mapped binding. This is what I call a Java-centric approach. It works with classes you define in your application rather than forcing the use of a set of generated classes. Although this is convenient for developers, it makes the framework's job more complex. The framework somehow needs to get data into and out of the application classes in a consistent manner, without forcing the application classes to follow a rigid model. This is where another of the differences between JiBX and the other data binding frameworks enters in.

Reflecting on performance
When a framework needs to get data into and out of a variety of Java language classes, the usual way of doing this is by using reflection. This is the approach taken by Castor, for instance, in its mapped binding support. is a way of accessing information about a Java language class at runtime. It can be used to access fields and methods in instances of a class, providing a way of dynamically hooking together classes at runtime without the need for any source code links between the classes.

Reflection is a great basis for many types of frameworks that work with Java classes, but it does have some drawbacks when used for data binding. For one thing, it generally requires you to use public fields or methods in your classes to allow reflection to operate properly. This means you need to provide access to internal state information as part of your public API, when really it should only be accessible by the binding framework. Reflection also suffers a performance disadvantage when compared to calling a method or accessing a field directly in compiled code.

Because of these limitations I wanted to avoid using reflection for data binding in JiBX. The developers of the Java Data Objects (JDO) specification had faced similar problems in moving data between Java language objects and databases. In their case, they avoided using reflection by instead working directly with class files, adding code to the classes generated by the compiler in order to provide direct access for the framework. I chose to use this same approach for JiBX.

Enhancing class files
The JDO team came up with a great term to describe the process of munging (see Resources) the class files generated by a compiler: "Byte code enhancement." Sounds much better than saying your class files are being "mangled" or "implanted", doesn't it? I don't think I can improve on the term, so I'm just shamelessly expropriating it for use by the JiBX framework as well.

The actual class file modifications are done by a JiBX component called the binding compiler. The binding compiler is executed at program assembly time -- after you've compiled your Java language source code to class files, but before packaging or executing the class files. The binding compiler reads one or more binding definition documents (see Defining bindings). For each class included in any of the bindings it adds the appropriate marshalling or unmarshalling code.

In general, you get a pair of added methods in your bound class files for each marshalling or unmarshalling binding that includes that class. There are some exceptions to this -- if a class is treated exactly the same way in multiple bindings those bindings reuse a single set of methods, and some types of binding operations may require more or fewer added methods. Four methods per binding (two for marshalling, two for unmarshalling) is about the average, though.

The binding compiler also generates some added support classes that go along with the added methods. Basically, one small helper class is added for each class that's included in any of the bindings, along with a separate class per binding. In the special case of unmarshalling forward references to objects identified by an ID value, the equivalent of a small inner class is also generated to fill in the value of the forward-referenced object once it's been unmarshalled.

Normally the total number of added classes and the total size of the added code is fairly small. The sample you can download from the JiBX site includes an example based on the Part 2 test code (see Resources). This generates 6 added classes and 23 added methods, with a total added size of 9 KB, to handle a binding involving 5 classes. This sounds like a lot -- but compare this with other alternatives based on code generation from a grammar in Figure 1. This shows the total code size for JiBX, including both base classes and the added binding code, compared with the total generated code size for the other frameworks. Only Quick is able to do better than JiBX in code size.

Figure 1. Binding code comparison
Binding code comparison

Defining bindings
The JiBX binding compiler described in the last section works from binding definitions that you supply. Binding definitions are themselves XML documents, with a DTD grammar included in the download. Unlike most other data binding frameworks, JiBX supports using any number of binding definitions in combination. You can, for instance, unmarshal a document using one binding, make changes, then marshal the data objects to an output document using a different binding.

A binding definition lets you control such basic details as whether a particular simple property of a class (such as a primitive value, or a String) is mapped to an element or to an attribute in the XML document, and the name used for that element or attribute. You can also tell JiBX how to access that property -- either as a field (which can have any access qualifier, including private) or as a JavaBean-style property with get and set methods. You can even specify values as optional, and define formatters for converting simple values to and from text.

However, JiBX goes beyond this simple form of mapping. Other data binding frameworks generally force each XML element with complex content (attributes or child elements) to be mapped to and from a distinct object, so that your object model directly matches the layout of your XML documents. With JiBX you can be more flexible: Child elements can be defined using a subset of the properties of an object, and properties of a referenced object can be included directly as simple child elements or attributes of the current element. This lets you make many types of changes to either your class structure or your XML document structure without needing to change the other to match.

Structure mapping
I call this type of mapping, where XML elements do not correspond directly to Java language objects, a structure mapping. For a simple example of how this works with JiBX, consider the following XML document:

Listing 1. Sample XML document

<customer>
  <name>
    <first-name>John</first-name>
    <last-name>Smith</last-name>
  </name>
  <street1>12345 Happy Lane</street1>
  <city>Plunk</city>
  <state>WA</state>
  <zip>98059</zip>
  <phone>888.555.1234</phone>
</customer>

Most data binding frameworks support mapping this document to instances of classes along the lines of:

Listing 2. Classes matching document structure

public class Customer {
  public Name name;
  public String street1;
  public String city;
  public String state;
  public String zip;
  public String phone;
}

public class Name {
  public String firstName;
  public String lastName;
}

Most frameworks also allow you to change the names of the fields, to use customerName instead of name, and first rather than firstName, for example. Some frameworks also use get/set methods rather than the public fields shown here, but the principle remains the same.

What most frameworks will not allow you to do is to bring the values within the name element into the object that corresponds to the customer element. In other words, you can't map the XML to this class:

Listing 3. Same data in a single class

public class Customer {
  public String firstName;
  public String lastName;
  public String street1;
  public String city;
  public String state;
  public String zip;
  public String phone;
}

Nor can you map the XML to a pair of classes like these:

Listing 4. Classes with different structure

public class Customer {
  public String firstName;
  public String lastName;
  public Address address;
  public String phone;
}

public class Address {
  public String street1;
  public String city;
  public String state;
  public String zip;
}

JiBX does allow you to do this type of mapping. This means the structure of your objects is not tied to the structure of the XML -- you can restructure your object classes without needing to change the XML format used for external data transfer. I'll give you specifics on this (including actual mapping files for the above pair of examples) in the next article in this series.

Conclusions
The basic architecture of JiBX is very different from those of other XML data binding frameworks for Java applications. This leads to both advantages and drawbacks when comparing JiBX with these other frameworks. On the plus side, JiBX gains the advantages of very fast operation, a compact runtime, and greater isolation between XML document formats and Java language object structures. On the minus side, it's based on a relatively unproven parser technology and does not support the validation flexibility provided by some of the alternatives (especially JAXB).

Some of the other differences between JiBX and alternative frameworks are less clear-cut. For instance, JiBX's technique of class file enhancement offers the advantage of keeping your source code clean -- the binding code is added after you compile, so you never need to deal with it directly -- but at the costs of an added step in the build process and potential confusion in tracking problems in your code accessed during marshalling or unmarshalling. For some users and applications, one or another of these factors will be more important than others.

Part 4 of this series will dive into the details of using JiBX in your applications. Once I've shown you how to use it I'll also return to this issue of what I see as JiBX's weaker points, and go on to suggest some possible ways in which these can be strengthened in the future. Check out Part 4 to get the rest of the JiBX story!

Resources

  • Learn more about the new JiBX framework for mapped bindings.

  • Part 1 of this series on data binding provides background on why you'd want to use data binding for XML, along with an overview of the available Java frameworks for data binding. Part 2 gives performance comparisons between the data binding frameworks, including the new JiBX framework (developerWorks, January 2003).

  • Check out the author's prior article on "Data Binding with Castor," which covers the mapped data binding technique with Castor (developerWorks, April 2002).

  • If you need background on XML, try the developerWorks "Introduction to XML tutorial" (August 2002).

  • Review the author's previous developerWorks articles covering performance (September 2001) and usage (February 2002) comparisons for Java XML document models.

  • Go to the source(Forge) to find out about the widely used SAX2 parser API for push parsing XML.

  • Learn about the fast and flexible XmlPull parser API developed by some of the leading pull parser researchers.

  • Track the progress of the Java Specification Request for a Streaming API for XML (StAX).

  • Read Brett McLaughlin's overview of Quick in "Converting between Java objects and XML with Quick," which shows you how to use this framework to quickly and painlessly turn your Java data into XML documents, without the class generation semantics required by other data binding frameworks (developerWorks, August 2002).

  • Find out more about the Java Architecture for XML Binding (JAXB), the evolving standard for Java Platform data binding.

  • Take a closer look at the Castor framework, which supports both mapped and generated bindings.

  • The Quick framework is based on a series of development efforts that predate both the Java Platform and XML. It provides an extremely flexible framework for working with XML on the Java Platform.

  • Explore the details of Zeus, which (like Quick) generates code based on DTD descriptions of XML documents, but is simpler to use -- and more limited -- than Quick.

About the author
Photo of Dennis SosnoskiDennis Sosnoski (dms@sosnoski.com) is the founder and lead consultant of the Seattle-area Java consulting company Sosnoski Software Solutions, Inc., specialists in J2EE, XML, and Web services support. Dennis's professional software development experience spans over 30 years, with the last several years focused on server-side Java technologies. He's a frequent speaker on XML in Java and J2EE technologies at conferences nationwide, and chairs the Seattle Java-XML SIG.


88KBe-mail it!

What do you think of this document?
Killer! (5) Good stuff (4) So-so; not bad (3) Needs work (2) Lame! (1)

Comments?



developerWorks > XML | Java technology
developerWorks
  About IBM  |  Privacy  |  Terms of use  |  Contact