ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Hangin' with the JAX Pack, Part 1
Pages: 1, 2

JAXB -- Java Architecture for XML Data Binding

Current specification status: Current Version 0.21, with early access reference implementation.



JAXB (JSR 31) provides a similar conceptual mechanism to JAXP's wrapping of XML with Java objects. In fact JAXB is two things -- a toolset for creating a two-way mapping between XML and Java, and an API for accessing XML/Java objects.

A word of caution: currently, the JAXB specification is a working draft and potentially subject to substantial change.

Typically applications create, consume, and otherwise change XML data. While you could certainly write an application that used DOM or SAX to process data, such an application would be error-prone and tedious to develop. And ultimately, many developers would be doing the same thing for the same XML/DTD or schema combination.

What JAXB provides is a mechanism for generating the binding between arbitrary DTDs and schema into equivalent Java objects. The JAXB specification defines three specific areas of support:

  • The unmarshalling of XML documents into a representative object tree
  • The marshalling of trees representing XML data back into XML documents
  • The validation of trees representing XML data against defined constraints

In this article we will focus primarily on the ability of JAXB to generate Java classes that marshal and unmarshal XML into Java objects.

If we look more closely into the JAXB specification, we see that its power comes from its binding framework. The binding framework defines the abstract classes and interfaces that are implemented when we run the schema compiler. Specifically, the binding framework is composed of two packages: java.xml.marshal defining low-level primitives and clases for reading and writing XML; and java.xml.bind providing higher-level interfaces for marshalling, unmarshalling, and validating XML into and out of Java objects.

The marshal package provides a variety of subclasses for reading from files, streams, SAX and DOM trees. etc., all adding exceptional power to your JAXB-based applications.

More genererally, the javax.xml.bind package defines a number of classes including:

Unmarshallers
Populate Java objects from XML
Marshallers
Support generating XML from Java objects
Validators
Validate and re-validate Java classes to determine if they conform to the underlying DTD or schema
Dispatchers
Map XML data to Java objects

Rather then continue to pore through the JAXB specification, an example might be more illustrative of these concepts.

The early access version of JAXB comes with a number of examples, the simplest of which is a traditional trade example whose DTD is shown below:

Listing 4: Stock.xml

<?xml version="1.0" encoding="US-ASCII"?>

<!--
A simple stock-trade DTD
@(#)trade.dtd 1.3 01/03/07
!-->

<!-- #[START] -->
<!ELEMENT trade ( symbol, quantity, limit?, stop?, date ) >

<!ATTLIST trade
account CDATA #REQUIRED
action ( buy | buy-to-cover | sell | sell-short ) #REQUIRED
duration ( immediate | day | good-til-canceled ) "day" >

<!ELEMENT symbol (#PCDATA) >
<!ELEMENT quantity (#PCDATA) >
<!ELEMENT limit (#PCDATA) >
<!ELEMENT stop (#PCDATA) >
<!ELEMENT date (#PCDATA) >

Basically, trades contain the information we expect from a trade: the symbol, quantity, date, etc., as well as various trade attributes. If we run the schema compiler on the trade DTD, it generates a single class, Trade.java, a snippet of which is shown below:

Listing 5: Trade.java

/* Various imports removed */
import java.io.InputStream;
import javax.xml.bind.ConversionException;
import ...
/* Various imports removed */


public class Trade
    extends MarshallableRootElement
    implements RootElement
{

    private String _Account;
    private String _Action;
    private String _Duration;
    private boolean isDefaulted_Duration = true;
    private final static String DEFAULT_DURATION = String.valueOf("day");
    private String _Symbol;
    private String _Quantity;
    private String _Limit;
    private String _Stop;
    private String _Date;

    public String getAccount() {
        return _Account;
    }

    public void setAccount(String _Account) {
        this._Account = _Account;
        if (_Account == null) {
            invalidate();
        }
    }

. . .
}

As one would expect, the trade DTD generated a number of fields corresponding to the fields and attributes of the DTD, as well as an equals method and marshal and unmarshal methods. But how do we go about using the newly created trade class?

Let's look at the driver application for the Tradelister.java trade class packaged with JAXB.

Listing 6: Tradelister.java

00 import java.io.*;
01 import javax.xml.bind.*;
02 public class TradeLister {
03    public static void main(String[] args) throws Exception {
04	      Dispatcher d = Trade.newDispatcher();
05	      Object ob = d.unmarshal(System.in);
06	      System.out.println(ob);
07    }
08 }
Tradelister first imports the required support classes from javax.xml.bind and then creates a new dispatcher for trades. Tradelister then unmarshals any trade classes passed in via System.in. What is actually happening is that a newDispatcher() factory method (inherited by the Trade class generated from the trade.dtd) allows us to generate, in memory, representations of trades. We can use this factory method to instantiate Dispatcher objects, which are capable of marshalling and unmarshalling XML data. The object actually returned by unmarshal is in fact a Trade object. It would have been perfectly reasonable to code TradeLister as:

Listing 7: Tradelister2.java

00 import java.io.*;
01 import javax.xml.bind.*;
02 public class TradeLister2 {
03    public static void main(String[] args) throws Exception {
04	      Dispatcher d = Trade.newDispatcher();
05	      Trade ob = (Trade)d.unmarshal(System.in);
06	      System.out.println(ob);
07    }
08 }

We could have then accessed the various Trade fields via their JavaBeans, like getters and setters. Likewise, if the Trade object contained child objects, we would obtain each via similar getters and setters.

The JAXB specification goes into a great level of detail about how marshalling and unmarshalling actually occur; interested readers should look more closely at the specification for more information.

Conclusion

The JAX Pack APIs add an exciting element to Web services development in a J2EE environment. In this article we saw how to access DOM, SAX, and XSLT without concern for the underlying provider, via JAXP. We saw how to wrap XML in Java Objects via JAXB. In the next article, we'll learn how to send XML messages using JAXM.

Al Saganich is BEA Systems' senior developer and engineer for enterprise Java technologies, focused on Java integration and application with XML and Web services.


Return to ONJava.com.