HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML

As more and more industries standardize their data formats around XML, Java developers are challenged to keep up. That's especially true of developers employing a document-centric programming model, where an evolving schema can expose brittleness in your code and leave you wishing for a better solution.

XML data binding relieves the pain of any Java programmer who has ever winced at having to work with a document-centric processing model. Unlike SAX and DOM, which force you to think in terms of a document's structure, XML data binding lets you think in terms of the objects the structure represents. It does so by realizing that structure as a collection of Java classes and interfaces.

This is especially valuable when lots of applications use the same document schemas. Then the data binding approach yields a set of standard classes and interfaces that are reused across all the applications. This saves work since you don't have to write, debug, and maintain code to extract data from XML. There are even more savings if you're developing an application for one of the many industries that have agreed on standard XML Schemas for business data interchange: finance, travel, auto, and retail, to name just four.

This article will look at two new standards: JAXB and UBL.

SAX and DOM
SAX and DOM are among the oldest programming models for managing XML data (perhaps only younger than the "desperate Perl hacker"). SAX (Simple API for XML) is a stream processor for XML that requires you to implement the org.xml.sax.ContentHandler interface. This interface defines a set of callbacks that you register with the SAX parser. The parser calls your methods as it encounters various tokens in the input stream.

SAX is fast, uses memory sparingly, and is useful for accessing just part of a document. It's less efficient, though, if you have to process the document more than once, or need to access document structures randomly, because it runs through the whole document instead of providing any navigational methods.

DOM (Document Object Model) provides a set of APIs for accessing an in-memory representation of the XML document. This representation forms a tree, which the application walks through looking for relevant information. DOM is useful if you need to edit an XML document, or access parts of it randomly. However, DOM implementations tend to be memory intensive, and sometimes even need to store the entire document in memory. This may not even be possible for very large documents.

Frequently, the goal of both SAX and DOM programmers is to initialize domain-specific objects with XML data. For example, given the element:

<Name first="John" last="Smith"/>

a SAX programmer would have to write a content handler and a DOM programmer would have to walk a parse tree to initialize an instance of this domain-specific class:

public class Name {
public String first;
public String last;

public String getFullName() {
return first + " " + last;
}
...
}

Having this instance gives other parts of the application access to XML data using domain-specific logic. However, you get there only by first dealing with the document's structure by way of SAX or DOM. XML data binding, on the other hand, automates this step.

XML Data Binding
XML data binding binds XML constructs directly to objects. Several open source projects for binding XML to Java have taken somewhat different approaches. The superset of their capabilities includes:

  • Generating Java source code from an XML document
  • Generating Java source code from an XML Schema (either DTD or XSD [XML Schema definition language])
  • Generating an XML document from an arbitrary set of Java objects
  • Unmarshaling an XML document (creating in-memory objects)
  • Marshaling an XML document (writing out an XML document from in-memory objects)
  • Validating an XML document, in its unmarshaled or marshaled form

    A recent standard, JAXB, standardizes the XML data binding interface.

    Java Architecture for XML Binding
    Java Architecture for XML Binding (JAXB) was developed in Java Specification Request (JSR) 31. It was written by an industry expert group under the auspices of the Java Community Process. By standardizing the XML data binding interface and providing a conformance test, JAXB allows you to choose among different XML binding implementations without having to rewrite your application. JAXB also comes with a standard implementation, which we'll use to show you how to bind the UBL schema to Java objects.

    UBL
    Universal Business Language (UBL) is an XML-based business language built upon existing EDI and XML business-to-business vocabularies. It's the product of the UBL Technical Committee of oasis. The committee intends to have UBL become an international standard for electronic commerce. If you're a J2EE programmer, there's a good chance UBL will be a part of your future.

    The latest UBL 0.7 release (see References) contains schema, sample XML documents, specifications, and documentation. It's perfect for experimenting with UBL applications. We're going to do just that using Java bindings generated by JAXB from the UBL schema.

    Compiling the UBL Schema into Java Using JAXB
    To compile the UBL schema into Java classes, download the Java Web Services Developer Pack 1.2 (see References). The Java WSDP is a free, integrated toolkit that allows Java developers to build, test, and deploy XML applications, Web services, and Web applications.

    Set JWSDP_HOME to the directory where you installed the Java WSDP. Change to $JWSDP_HOME/jaxb/samples/ubl. Create a directory named test, then run (xjc is JAXB's schema compiler):

    $JWSDP_HOME/jaxb/bin/xjc.sh -d test 0p70/xsd/*.xsd

    (You can also invoke xjc by way of an Ant task.) This creates the packages in test (see Listing 1).

    By default, xjc puts its output into Java packages with names derived from the schema's targetNamespace.

    Customizing the Package Names
    JAXB gives you control over the binding process with various customizations. These can be inline in the schema by way of XSD annotation elements, or can be put in their own file. In the latter case, JAXB's xjc uses xpath to identify which part of the schema the customization affects. For example, this customization:

    <jaxb:bindings
    schemaLocation="0p70/xsd/CoreComponentParameters.xsd"
    node="/xsd:schema">
    <jaxb:schemaBindings>
    <jaxb:package
    name="org.oasis.ubl.corecomponentparameters"/>
    </jaxb:schemaBindings>
    </jaxb:bindints>

    JAXB Package Name Customization

    puts the Java classes and interfaces created from CoreComponentParameters.xsd in the org.oasis.ubl.corecomponentparameters package.

    ubl.xjb contains this customization and similar ones for each of the UBL schemas. External customization is useful for customizing standard schemas. It allows customization of schemas that are considered read-only. It also allows groups sharing a schema to bind to Java differently based on the needs of each application.

    Create a directory named classes. Then compile the schema like this:

    $JWSDP_HOME/jaxb/bin/xjc.sh -b ubl.xjb -d classes 0p70/xsd/*.xsd

    This creates the packages in classes shown in Listing 2. See Chapter 10 of the Java Web Services Tutorial for more JAXB binding customizations.

    A Typical Binding
    UBL_Library_0p70_Reusable.xsd defines a number of types used throughout the UBL schema. For example, Listing 3 is a simplification of AddressType.

    JAXB binds AddressType to the Java interface shown in Listing 4. You'll find this interface in the directory:

    classes/org/oasis/ubl/commonaggregatetypes.

    This class file contains its implementation.

    classes/org/oasis/ubl/commonaggregatetypes/impl/
    AddressTypeImp.java

    Compiling the Generated Code
    It's easiest just to use Ant:

    $JWSDP_HOME/apache-ant/bin/ant compile-generated

    Creating the Javadoc

    $JWSDP_HOME/apache-ant/bin/ant javadoc

    JAXB's Javadoc is particularly useful since the generated interfaces contain Javadoc comments with the snippet of schema that's bound to them. You can use JAXB's Javadoc customization to add additional documentation.

    The PrintOrder Application
    The UBL sample in Java WSDP 1.2 reads in a UBL order instance, computes subtotals and a grand total, and prints the result to the screen. Sounds simple enough, but there's a lot going on. Here's how you run it:

    $JWSDP_HOME/apache-ant/bin/ant printorder

    This prints the itemized order to the screen, with subtotals for each item and a grand total for the order (see Figure 1).

    Joes Office Supply 32 W. Lakeshore Dr Chicago, IL
    Date: February 2, 2003

    Sold To: George Tirebiter
    c/o Bills Microdevices
    413 Spring St
    Elgin, IL 60123

    1. Part No.: 32145-12
    Description: Pencils, box #2 red
    Price: $2.50
    Qty.: 5
    Subtotal: $12.50

    2. Part No.: 78-697-24
    Description: Xeorox Paper- case
    Price: $30.00
    Qty.: 12
    Subtotal: $360.00

    3. Part No.: 091356-3
    Description: Pens, box, blue finepoint
    Price: $5.00
    Qty.: 10
    Subtotal: $50.00

    4. Part No.: 543-165-1
    Description: Tape, 1in case
    Price: $12.50
    Qty.: 3
    Subtotal: $37.50

    5. Part No.: 984567-12
    Description: Staples, wire, box
    Price: $1.00
    Qty.: 10
    Subtotal: $10.00

    6. Part No.: 091344-5
    Description: Pens, box red felt tip
    Price: $5.00
    Qty.: 5
    Subtotal: $25.00

    7. Part No.: 21457-3
    Description: Mousepad, blue
    Price: $0.50
    Qty.: 12
    Subtotal: $6.00

    Total: $501.00

    PrintOrder contains the main() (see Listing 5). It relies on three facade classes:

  • package samples.ubl.report;
  • import samples.ubl.report.facade.OrderFacade;
  • import samples.ubl.report.facade.OrderLineTypeFacade;
  • import samples.ubl.report.facade.AddressFacade;

    The Facade design pattern provides a simpler, higher-level interface. Typically, that's done to isolate an application from the complexity of the underlying subsystems. Here, our principle motivation is to isolate our application from changes to an evolving schema. Since we just wanted to print a simple report, our facades are read-only.

    A look at printBuyer() in PrintOrder shows that getting the name of the buyer contact (a person, usually) is just a matter of calling OrderFacade's getBuyerContact() method (see Listing 6).

    getBuyerContact() has a simple signature (see Listing 7). In this listing, order is a reference to org.oasis.ubl.order.Order, which is bound to <xsd:element name="Order" type="OrderType"/> inUBL_Library_0p70_Order.xsd. If that binding were to change, for example, such that order.getBuyerParty() returned PartyType, we could make this one-line change to getBuyerContact() without affecting PrintOrder:

    (BuyerPartyType)party = order.getBuyerParty();

    This pattern characterizes the other methods in OrderFacade and the methods in OrderLineTypeFacade and AddressFacade. And none of this code relies on org.w3c.dom or org.xml.sax interfaces.

    Conclusion
    JAXB makes it possible to process XML documents without using SAX or DOM. This saves us time when getting started and over the long haul since we don't have to debug and maintain a lot of tedious code devoted to traditional XML processing. While this is useful for any application that uses XML, it will be especially valuable in those application domains with defined XML Schemas for business data interactions.

    References

  • UBL0p70.zip: http://oasis-open.org/committees/ubl/lcsc/0p70/UBL0p70.zip
  • UBL Technical Committee: www.oasis-open.org/committees/tc_home.php?wg_abbrev=ubl
  • JSR 31: http://jcp.org/en/jsr/detail?id=31
  • Java Community Process: http://jcp.org/
  • JAXB home page: http://java.sun.com/xml/jaxb/index.html
  • Java Web Services Developers Pack 2.0: http://java.sun.com/webservices/webservicespack.html
  • Java Web Services Tutorial: http://java.sun.com/webservices/docs/ 1.1/tutorial/doc/index.html
  • Gamma, E., Helm, R., Johnson, R., and Vlissides, JM. (1998). Design Patterns CD: Elements of Reusable Object-Oriented Software. Addison-Wesley Professional.

    xjc: The JAXB Binding Compiler
    The Java WSDP comes with xjc.sh and an xjc.bat:

    $JWSDP_HOME/jaxb/bin/xjc.sh -help
    Usage: xjc [-options ...] <schema>
    Options:
    -nv : don't validate the input schema
    -extension : allow vendor extensions
    -b <file> : external bindings file
    -d <dir> : output generated files to <dir>
    -p <pkg> : target package
    -host <proxyHost> : set http.proxyHost
    -port <proxyPort> : set http.proxyPort
    -classpath <arg> : where to find user class files
    -help : display this help message

    The build.xml sets up the xjc target like this:

    <taskdef name="xjc" classname="com.sun.tools.xjc.XJCTask">
    <classpath refid="classpath"/>
    </taskdef>

    Common Applications of Binding Customization Resolving Name Collisions
    Since each XML namespace contains six symbol spaces, it's not uncommon for terminals in one symbol space to collide with those in another when JAXB tries to map them to Java. This inlined customization, which handles them automatically, illustrates the technique:

    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    ...
    <xsd:annotation>
    <xsd:appinfo>
    <jxb:schemaBindings>
    <jxb:nameXmlTransform>
    <jxb:elementName suffix="Element"/>
    </jxb:nameXmlTransform>
    </jxb:schemaBindings>
    <xsd:appinfo>
    </xsd:annotation>
    ...
    </xsd:schema>

    Customizing Names of Classes and Properties
    The text explains how we used an external binding customization to change the name of the packages used for the generated Java code. JAXB also lets you rename classes and properties.

    Setting Global Binding Behavior
    This illustrates only some of the possible global bindings:

    <globalBindings collectionType="indexed"
    fixedAttributeAsConstantProperty="true"
    generateIsSetMethod="true"/>

    This customization:

  • Represents collections as a JavaBean indexed property that also has a length() method (by default, JAXB collection properties are java.util.List).
  • Maps all fixed attributes as Java constants.
  • Generates an isSet method for JAXB properties with a primitive base type (such as int) or base type of List. The isSet method allows you to determine if the getter for an optional property is returning the property's default value or if it is returning a value set within the XML document. This helps you determine what was in the original XML document, although typically, JavaBeans don't care.

    Controlling the Binding of an XML Schema Element to its Java Representation as a Type-Safe Enumeration Class

    <jaxb:globalBinding

    typesafeEnumBase="xsd:string"/> can be used to customize the enumeration members and their values of simpleType with enumeration facets that derive by default from xsd:string (there's a default type-safe enumeration binding for NCName).

    About The Authors
    Ed Mooney is a staff engineer at Sun Microsystems, Inc. He's currently the project lead for the JAXB reference implementation. [email protected]

    Joseph Fialli is a senior staff engineer at Sun Microsystems. He is currently working on the next version of JAXB. Previously within Sun, he was the specification lead for JAXB v1.0, lead architect for Java Message Service API v1.0.2, and added enhancements to Java serialization within J2SE 1.2.
    [email protected]

    "XML Data Binding with JAXB and UBL"
    Vol. 8, Issue 6, p. 50

    	
    
    
    
    Listing 1
    
    oasis/names/tc/ubl/commonaggregatetypes/_1_0/_0
    oasis/names/tc/ubl/corecomponentparameters/_1_0/_0
    oasis/names/tc/ubl/corecomponenttypes/_1_0/_0
    oasis/names/tc/ubl/despatchadvice/_1_0/_0
    oasis/names/tc/ubl/invoice/_1_0/_0
    oasis/names/tc/ubl/order/_1_0/_0
    oasis/names/tc/ubl/ordercancellation/_1_0/_0
    oasis/names/tc/ubl/orderresponse/_1_0/_0
    oasis/names/tc/ubl/orderresponsesimple/_1_0/_0
    oasis/names/tc/ubl/receiptadvice/_1_0/_0
    
    Listing 2
    
    org/oasis/ubl/commonaggregatetypes
    org/oasis/ubl/corecomponentparameters
    org/oasis/ubl/corecomponenttypes
    org/oasis/ubl/despatchadvice
    org/oasis/ubl/invoice
    org/oasis/ubl/order
    org/oasis/ubl/ordercancellation
    org/oasis/ubl/orderresponse
    org/oasis/ubl/orderresponsesimple
    org/oasis/ubl/receiptadvice
    
    Listing 3
    
     1 <complexType name="AddressType">
     2   <complexContent>
     3     <restriction base="anyType">
     4       <sequence>
     5         <element ref="ID"/>
     6         <element ref="Postbox" minOccurs="0"/>
     7         <element ref="Building" minOccurs="0"/>
     8         <element ref="Floor" minOccurs="0"/>
     9         <element ref="Room" minOccurs="0"/>
    10         <element ref="Street" minOccurs="0"/>
    11         <element ref="AdditionalStreet" minOccurs="0"/>
    12         <element ref="HouseName" minOccurs="0"/>
    13         <element ref="HouseNumber" minOccurs="0"/>
    14         <element ref="InhouseMail" minOccurs="0"/>
    15         <element ref="Department" minOccurs="0"/>
    16         <element ref="CityName" minOccurs="0"/>
    17         <element ref="PostalZone" minOccurs="0"/>
    18         <element ref="CountrySub-Entity" minOccurs="0"/>
    19         <element ref="CountrySub-EntityCode" minOccurs="0"/>
    20         <element ref="Region" minOccurs="0"/>
    21         <element ref="District" minOccurs="0"/>
    22         <element ref="TimezoneOffsetMeasure" minOccurs="0"/>
    23         <element ref="Country" minOccurs="0"/>
    24       </sequence>
    25     </restriction>
    26   </complexContent>
    27 </complexType>
    
    Listing 4
    
     1 package org.oasis.ubl.commonaggregatetypes;
     2 
     3 public interface AddressType {
     4 
     5     org.oasis.ubl.corecomponenttypes.TextType getBuilding();
     6     void setBuilding(org.oasis.ubl.corecomponenttypes.TextType value);
     7     org.oasis.ubl.corecomponenttypes.TextType getPostalZone();
     8     void setPostalZone(org.oasis.ubl.corecomponenttypes.TextType value);
     9     org.oasis.ubl.corecomponenttypes.TextType getRoom();
    10     void setRoom(org.oasis.ubl.corecomponenttypes.TextType value);
    11     org.oasis.ubl.corecomponenttypes.TextType getAdditionalStreet();
    12     void setAdditionalStreet(
                              org.oasis.ubl.corecomponenttypes.TextType value);
    13     org.oasis.ubl.corecomponenttypes.TextType getDistrict();
    14     void setDistrict(org.oasis.ubl.corecomponenttypes.TextType value);
    15     org.oasis.ubl.corecomponenttypes.TextType getStreet();
    16     void setStreet(org.oasis.ubl.corecomponenttypes.TextType value);
    17     org.oasis.ubl.corecomponenttypes.TextType getPostbox();
    18     void setPostbox(org.oasis.ubl.corecomponenttypes.TextType value);
    19 
    20    // Remaining methods omitted ...
    21 }
    
    Listing 5: PrintOrder's main() Method
    
     1 public static void main(String[] args) {
     2     try {
     3         JAXBContext jc =
                  JAXBContext.newInstance(
                  "org.oasis.ubl.order:"
                  + "org.oasis.ubl"
                  + ".commonaggregatetypes");
     4         Unmarshaller u =
               jc.createUnmarshaller();
     5         Order order =
                  (Order) u.unmarshal(new
                         FileInputStream("0p70/xml/"
                         + "OfficeSupplyOrder"
                         + "Instance.xml"));
     6 
     7         OrderFacade of =
                new OrderFacade(order);
     8         printLetterHead(of);
     9         printDate(of);
    10         printBuyer(of);
    11         printLineItems(of);
    12     } catch (JAXBException e) {
    13         e.printStackTrace(System.out);
    14     } catch (IOException ioe) {
    15         ioe.printStackTrace();
    16     }
    17 }
    
    Listing 6: PrintOrder's printBuyer() Method
    
     1 private static void printBuyer(
          OrderFacade order) {
     2     AddressFacade addr =
          order.getBuyerAddress();
     3     System.out.println("\nSold To: "
          + order.getBuyerContact()
          + "\n         c/o "
          + order.getBuyerName()
          + "\n         "
          + addr.getStreet()
          + "\n         "
          + addr.getCity()
          + ", "
          + addr.getState()
          + "  "
          + addr.getZip());
    4 }
    
    Listing 7: OrderFacade's getBuyerContact() Method
    
    1  public String getBuyerContact() {
    2   BuyerPartyType party = order
    	     .getBuyerParty();
    3    if (party != null) {
    4     if (party.getBuyerContact() != null) {
    5         return party.getBuyerContact()
    	               .getName() != null
    	             ? party.getBuyerContact()
    	               .getName().getValue()
    	            : null;
    6    }
    7  }
    8  return "";             
    9 }
    
     
    

    All Rights Reserved
    Copyright ©  2004 SYS-CON Media, Inc.
      E-mail: [email protected]

    Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.