Part 3 of this series gave you an introduction to the architecture of the JiBX data binding framework. That included a quick overview of JiBX's Java-centric approach to data binding, as contrasted with the XML-centric approach used by most other data binding frameworks. Now in Part 4, you'll find out how to use the power of this Java-centric approach to data binding in your applications.
Most other data binding frameworks for the Java language force you to supply a DTD or W3C XML Schema grammar for your documents, then generate a collection of classes from that grammar. You need to work with these generated classes to use the frameworks, but in most cases you have little or no control over the classes -- they're basically JavaBean-type wrappers around simple data structures along with some added framework code. The whole point of these generated classes is to provide an interface for working with data from your XML documents.
The JavaBean wrapper approach is sometimes presented as object-oriented because of the use of get/set methods to access data. In reality, it's about as far from true object-oriented development as you can get, because of the lack of extensibility in the data objects. True object-oriented programming means that objects hide their internal state and implement their own behaviors for working with that state information. This is typically not possible with the generated code approaches.
With JiBX, binding to XML is treated as an aspect that applies to your classes, not as the primary purpose of those classes. Thus, you use object-oriented designs that are appropriate to your application. It also gives you the freedom to refactor your classes without needing to change the bound XML document structure. This aspect-oriented approach even lets you define multiple bindings to be used with the same classes, so that you can work with multiple input or output XML document structures without having to change your code.
The core of JiBX's aspect-oriented approach to binding is the use of binding definitions to control how your Java objects are converted to and from XML documents. To see how this works, think of XML documents as tree structures, where the nesting of elements define branches of the tree. Data binding converts these XML trees to and from trees of objects (or sometimes graphs of objects, with links up or across the tree structure). A JiBX binding definition is a third tree that represents a merger of the structure of the XML and object trees (which, in JiBX, can be different). This merged structure tells JiBX how to convert the XML tree to and from the object tree.
Figure 1 gives a simple example of how the binding definition is used in the JiBX framework.
In this case the XML document and the bound classes use the same structure -- a
as a child, and the
has a pair of
simple text values as children. The binding definition simply duplicates this
structure, supplying the necessary information at each level to relate XML
elements to the corresponding object properties.
Figure 1. Binding definition role
Several types of elements are used within a binding definition. The purposes of these elements and the types of child elements they can contain are shown in Table 1.
Table 1. Elements used in a binding definition
The root element of the binding definition, with optional attributes for binding name and global settings.
Namespace declaration that defines a namespace URI and associated prefix (with the prefix used for marshalling).
Format definition for converting simple values to and from text. This is needed only if you want to use nonstandard conversions.
Defines how objects of a particular class are converted to and from
XML. Each mapping is a reusable component that can be referenced wherever an
object of that type needs to be handled within the binding definition. Mapping
definitions that are children of the
Gives the conversion handling for a simple value (a primitive, or an object type with a format supplied) to convert it to and from text. The XML representation can be an attribute, a simple element, or in some cases a plain text or CDATA node.
Structure component of binding, which can represent a Java object, an XML element, or both. Usually, this represents both a Java object and an XML element linked to that object. A structure mapping is defined when either the object or the XML element is missing from the definition.
Children: any combination of
Similar to a
Children: any combination of
element is always the root element of a binding
definition. As children it can have
elements, which must be in that order (with the first two types
element can in turn have these same types of
elements as children for nested definitions, followed by a mixture of
elements that define the
details of the relationship between XML and a Java class.
elements represent simple value components of the XML
document, which can be attributes, simple child elements (with only text content),
text, or CDATA. The
elements are more involved. In the most
common case (as in the Figure 1 example), a
a child element with complex content (the
element, in the example)
to an object-value property of a Java object (the
name field of the
Customer object). Both sides of the relationship are optional,
though. This allows the
element to define an XML element with
no corresponding object, or an object with no corresponding element. I'll show
how this works in the following examples.
In Part 3, I gave some examples of the flexibility JiBX provides with structure mapping. I'll go through the actual binding definitions here. Figure 2 shows the first example, with a direct correspondence between the structure of the XML documents and the Java objects. This is just the full version of the same document and class structure used in Figure 1. Listing 1 gives a full binding definition for this correspondence.
Figure 2. Direct correspondence to XML
Listing 1. Binding definition for direct correspondence
<binding> <mapping name="customer" class="Customer"> <structure name="name" field="name"> <value name="first-name" field="firstName"/> <value name="last-name" field="lastName"/> </structure> <value name="street1" field="street1"/> <value name="city" field="city"/> <value name="state" field="state"/> <value name="zip" field="zip"/> <value name="phone" field="phone"/> </mapping> </binding>
Listing 1 gives the full form of the binding definition. This isn't the only way of specifying a binding, though. If requested, JiBX (starting with Beta 2) will map unspecified simple properties of Java objects automatically. The properties to be mapped may take the form of either fields or JavaBean-style get/set methods. Taking advantage of this default mapping allows Listing 2 to be used as a (much shorter) alternative to the Listing 1 definition.
Listing 2. Compact version of binding definition
<binding auto-link="fields"> <mapping name="customer" class="Customer"> <structure name="name" field="name"/> </mapping> </binding>
This compact approach does have some limitations. The automatically generated
property bindings will always follow any definitions given explicitly, and will
occur in the order they're defined. In the case of the Figure 1 binding this is just
what I want -- the
element is the first child of the
element, and the field definitions within both the
Customer classes use the same order as the corresponding XML
child elements. When the Java data matches the XML structure as closely as in
this case, automatically generating bindings can make the binding
definition very simple.
JiBX does provide some specialized options for customizing the automatic property binding generation. These let you give a prefix and suffix to be stripped from field or JavaBean property names when generating the corresponding XML element or attribute names, control the style of XML names, and set the access level for fields or methods included in the automatic generation. You can even list field or property names to be specifically included or excluded in the automatic generation. However, for the rest of the examples in this article I'll just stay with the full binding definition format, in order to clearly show exactly what values are being bound.
The simple binding example doesn't really do justice to the flexibility of JiBX. In Part 3 I also showed a pair of examples of structure mapping, which handles structural differences between the XML document and the bound Java classes. Figure 3 shows the first example of this type, with the same XML document structure bound to a single class rather than the pair of classes used previously.
Figure 3. Binding to single class
In the Figure 3 example, the Java class structure is a flattened version of
the XML document. Rather than using a separate class for the values within the
element, this just includes the values directly within the
class that corresponds to the parent
element. Listing 3 gives a
full binding definition for this structure mapping.
Listing 3. Structure mapping to single class
<binding> <mapping name="customer" class="Customer"> <structure name="name"> <value name="first-name" field="firstName"/> <value name="last-name" field="lastName"/> </structure> <value name="street1" field="street1"/> <value name="city" field="city"/> <value name="state" field="state"/> <value name="zip" field="zip"/> <value name="phone" field="phone"/> </mapping> </binding>
If you compare Listing 1 and Listing 3 you'll see that the change to the
binding definition for this flattened mapping is trivial. Only one line of the binding definition is
different -- the
attribute has been removed from the original version.
This tells JiBX that the
element of the binding definition defines an
element in the XML (as shown by the
attribute) that maps to some
properties of the current object.
Figure 4 gives a second example of structure mapping. This time the Java
class structure uses a pair of classes, but the breakdown of data values doesn't
match the structure of the XML document -- data values from the
element of the XML document are split between the two classes, and the values
child element are included directly in the class corresponding
to its parent element.
Figure 4. Binding to split classes
Listing 4 gives the full form of a binding definition for the Figure 4 binding.
The only difference from the Listing 3 binding definition is that I've added a
element corresponding to the new
element includes a
attribute but no
attribute, telling JiBX that the
element is defining an object
property with no corresponding element in the XML document.
Listing 4. Structure mapping to split classes
<binding> <mapping name="customer" class="Customer"> <structure name="name"> <value name="first-name" field="firstName"/> <value name="last-name" field="lastName"/> </structure> <structure field="address"> <value name="street1" field="street1"/> <value name="city" field="city"/> <value name="state" field="state"/> <value name="zip" field="zip"/> </structure> <value name="phone" field="phone"/> </mapping> </binding>
JiBX binding definitions offer many options beyond what I've covered here. Some
of these are hinted at in the list of binding definition elements, such as
custom serialization and deserialization using the
easy namespace handling with the
element. Other options are
controlled by attributes of the binding definition elements. These include
defaults for optional values, methods to be called before marshalling or after
unmarshalling objects, and identifier values for referencing objects.
JiBX also includes a general extension hook in the form of custom marshal and unmarshal method definitions. These let you take over complete control of the marshalling and unmarshalling process, working directly with the low-level methods defined by the JiBX context classes. This type of low-level operation is not intended for general usage. It does provide some interesting possibilities for JiBX add-ons, though. One potential use is to allow portions of a document to be mapped to and from a document model (such as DOM, JDOM, or dom4j). This would provide easy handling of special cases, such as XHTML fragments embedded within XML documents.
Once you've got your binding definition, you need to actually compile it into the
class files. JiBX supplies a binding compiler for this purpose. To use it,
you just set up the Java class path so both the jar files included in the JiBX
distribution and your own classes are accessible to the JVM, then run the
org.jibx.binding.Compile program with one or more binding definition
file paths as arguments.
The binding compiler adds JiBX binding code to your class files, preparing them for use with the JiBX runtime. It's smart about how it does this: If the same added code is needed by more than one binding, the binding compiler only generates the code once. Likewise, if you rerun the compiler with a modified binding definition it replaces the methods added for the old binding rather than just adding new ones. The compiler even removes methods and classes that were previously added for a binding you're no longer using. Finally, it only writes to class files that have actually been changed. This makes it safe to rerun the binding compiler after changing (and compiling) some of your Java source code files, without needing to recompile all your Java source files.
Once the binding compiler has modified your Java class files, you're ready to use the JiBX runtime for marshalling and unmarshalling documents. There's just one hitch, though: The actual binding code isn't added until after your Java source code is compiled to class files and run through the JiBX binding compiler, so you can't access this binding code directly in your source code. Instead, you need to work through a portion of the JiBX runtime that tracks the binding definitions you're using and connects you to the proper code at runtime.
This uses the
org.jibx.runtime.BindingDirectory class that's
included in the JiBX runtime jar, along with a class that JiBX generates in the
same package as your code (or as the first class file it modifies, if your code
is spread across multiple packages). You don't need to worry about the details of
getting at this generated class, though; instead, you access it by passing one of the
classes defined by a global mapping (one that's a child of the root
element) in your binding to the
BindingDirectory (if you've
compiled more than one binding into the code, you'll also need to pass the name
of the binding you want to use). The code is simple:
IBindingFactory bfact = BindingDirectory.getFactory(Customer.class);
Customer is the name of a class with a global mapping in
the binding. The
org.jibx.runtime.IBindingFactory interface that gets
returned provides methods to construct marshalling and unmarshalling contexts,
which in turn allow you to do the actual marshal and unmarshal operations.
Here's an unmarshal example:
IUnmarshallingContext uctx = bfact.createUnmarshallingContext(); Object obj = uctx.unmarshalDocument (new FileInputStream("filename.xml"), null);
This is just one of several variations of an unmarshal call -- in this case to
unmarshal an XML document in the file filename.xml. You can pass a
reader instead of a stream as the source of the document data, and you can also
specify an encoding for the document -- see the JavaDocs on the JiBX site for details. The
returned object is an instance of one of your classes defined with a global
mapping in the binding -- you can either check the type with
or cast directly to your object type, if you know what it is.
Marshalling is just as easy. Here's an example:
IMarshallingContext mctx = bfact.createMarshallingContext(); mctx.setIndent(4); mctx.marshalDocument(obj, "UTF-8", null, new FileOutputStream("filename.xml"));
As with the unmarshal example, this is just one of several variations that can be used for the marshal call. It first sets the indentation of the output XML to 4 spaces per nesting level, then marshals the object to an XML document written to the file filename.xml with UTF-8 character encoding (the most common choice for XML). You can pass a writer instead of a stream, as well as some other variations -- again, see the JavaDocs on the JiBX site for details. The object to be marshalled must be an instance of a class that's defined with a global mapping in the binding.
JiBX provides a number of advantages over other available XML data binding frameworks for Java applications. These include very fast operation, a compact runtime distribution, and greater isolation between XML document formats and Java language object structures. As JiBX nears initial production release, it's looking like a great alternative for many applications.
JiBX does still have some areas of weakness. One is the current lack of support for code generation from an XML grammar. That may seem a surprising comment after my earlier remarks on the limitations of the XML-centric code generation approaches, however JiBX actually offers the means to avoid many of these limitations. If an XML grammar could be used for generating an initial set of classes and a corresponding binding definition, this would provide the benefit of getting working code quickly. At the same time, users would still have the long-term flexibility to independently refactor either the code or the grammar while modifying the binding definition to keep everything working in harmony.
Another very useful feature would be a tool to verify a binding definition against an XML grammar. A grammar provides most of the information necessary to say whether a binding definition will actually handle the intended documents properly. A tool to actually check the combination for compatibility would help prevent potential surprises in testing or deployment.
The current byte code enhancement approach that adds binding framework methods to your compiled classes is also an area where more flexibility would be useful. Byte code enhancement offers the advantage of keeping your source code clean, 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. It'd be great to offer an alternative for cases where these costs outweigh the benefits.
I think there's a relatively simple solution to this issue. It should be fairly easy to decompile the code added by JiBX back to source code, and merge this into the original Java language source files. Once this is done the methods needed by JiBX will be compiled-in automatically, and as long as the user doesn't tinker with the code added by JiBX there should be no need to rerun the binding compiler until the binding definitions change. I'm currently investigating adding support for this type of operation to JiBX, though it probably won't be until after the initial production release.
As a final note on its limitations, JiBX currently offers relatively weak validation support compared to many of the other data binding frameworks. It's possible that this will change in the future. JiBX does include support for methods to be called before an object is marshalled or after an object is unmarshalled, and these methods could be used to handle most forms of validation. For many XML applications, full validation support is secondary to the main goal of fast and convenient access to data from XML documents, and for this goal JiBX already offers a great alternative.
In this article I've shown you the basics of working with the JiBX data binding framework. I personally feel JiBX has a lot to offer (which isn't too surprising, since I am the author of JiBX!). It's especially useful for applications that need to adapt existing object structures to XML, and for any applications where you want to decouple your code from the actual XML structure. But JiBX is definitely not a solution to all XML requirements for Java applications.
XML is used for many different purposes, and the ever-increasing number of tools for working with XML in Java applications reflects the fact that different purposes require different tools. The toughest part of working with XML is often just knowing which tool is best for a specific application. JiBX is designed to suit applications that need to interpret XML documents as data and work with that data in memory, where the focus is more on the use of that data by the application than on the XML documents themselves.
If JiBX sounds like a match for your needs I encourage you to download the current distribution and give it a try. Since it's an open source project with a BSD-style license, you're free to modify the code to suit your requirements -- and you don't even need to make your modifications public. I naturally hope that many people find it useful, and that they do contribute extensions and added tools to help the project grow in the future.
In my next article, I'll close out this series on data binding with a look at the recently released JAXB data binding standard and reference implementation. This will include trying out some of the customization options JAXB provides. JAXB is strongest in the very areas where JiBX is weakest, so this final article will be a nice wrap-up to a series that's covered a full range of tools and techniques.
- 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). Part 3 introduces the JiBX architecture and discusses the reasons behind the choices made in JiBX (developerWorks, April 2003).
- 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.
- 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.
- Read more about the interplay of Java Technology and XML.
- Reference JSR 31 - the XML Data Binding Specification.
- Find more information on the technologies covered in this article at the developerWorks
XML and Java technology zones.
IBM trial software: Build your next development project with trial software available for download directly from developerWorks.
- Find out how you can become an IBM Certified Developer in XML and related technologies.
Dennis Sosnoski (email@example.com) is the founder and lead consultant of 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.