Skip to main content

skip to main content

developerWorks  >  Java technology | XML | Open source  >

JiBX 1.2, Part 1: Java code to XML schema

Improve schema quality with custom conversion of Java data models to and from XML documents

developerWorks
Go to the previous pagePage 3 of 11 Go to the next page

Document options
PDF format - Fits A4 and Letter

PDF - Fits A4 and Letter
188 KB (29 pages)

Get Adobe® Reader®

Sample code


My developerWorks needs you!

Connect to your technical community


Rate this tutorial

Help us improve this content


Generating default binding and schema from code

Non-Java 5 usage

The tutorial example code uses Java 5 typed collection and enum features, but JiBX itself is fully compatible with older Java versions. The standard JiBX runtime works with 1.3 and later JVMs and can also be built for J2ME compatibility. Most of JiBX's other components, including BindGen, can be run on 1.4.1 and later JVMs. The BindGen documentation in the JiBX download includes an example showing how customizations can supply BindGen with the equivalent of typed collections when you use pre-Java 5 code.

It's easy to generate a JiBX binding definition, and the corresponding XML schema definition, from Java code. You'll learn how in this section.

Introducing the Java example code

As an example, I'll start with the Java code for a set of bean-style (private fields, public get and set access methods) classes used to represent an order from an online store. Listing 1 shows an abbreviated version of the code, with most of the get/set methods left out. The full sample code is in the sample code's src directory.


Listing 1. Base Java code
 
package org.jibx.starter;

/**
 * Order information.
 */
public class Order
{
    private long orderNumber;
    private Customer customer;

    /** Billing address information. */
    private Address billTo;
    private Shipping shipping;

    /** Shipping address information. If missing, the billing address is also used as the
     shipping address. */
    private Address shipTo;
    private List<Item> items;

    /** Date order was placed with server. */
    private Date orderDate;

    /** Date order was shipped. This will be <code>null</code> if the order has not
     yet shipped. */
    private Date shipDate;
    private Float total;

    public long getOrderNumber() {
        return orderNumber;
    }
    ...
}
/**
 * Customer information.
 */
public class Customer
{
    private long customerNumber;

    /** Personal name. */
    private String firstName;

    /** Family name. */
    private String lastName;

    /** Middle name(s), if any. */
    private List<String> middleNames;
    ...
}
/**
 * Address information.
 */
public class Address
{
    /** First line of street information (required). */
    private String street1;

    /** Second line of street information (optional). */
    private String street2;
    private String city;

    /** State abbreviation (required for the U.S. and Canada, optional otherwise). */
    private String state;

    /** Postal code (required for the U.S. and Canada, optional otherwise). */
    private String postCode;

    /** Country name (optional, U.S. assumed if not supplied). */
    private String country;
    ...
}
/**
 * Order line item information.
 */
public class Item
{
    /** Stock identifier. This is expected to be 12 characters in length, with two
     leading alpha characters followed by ten decimal digits. */
    private String id;

    /** Text description of item. */
    private String description;

    /** Number of units ordered. */
    private int quantity;

    /** Price per unit. */
    private float price;
    ...
}
/**
 * Supported shipment methods. The "INTERNATIONAL" shipment methods can only be used for
 * orders with shipping addresses outside the U.S., and one of these methods is required
 * in this case.
 */
public enum Shipping
{
    STANDARD_MAIL, PRIORITY_MAIL, INTERNATIONAL_MAIL, DOMESTIC_EXPRESS,
    INTERNATIONAL_EXPRESS
}



Back to top


Generating the default binding and schema

To generate a JiBX binding and XML schema from some Java classes, you first need to compile the classes, then run the org.jibx.binding.generator.BindGen tool included in the jibx-tools.jar from the JiBX distribution. You can run the tool directly from the command line or indirectly via a build tool such as Ant.

The tutorial download includes an Ant build.xml script with the compile target to compile the example code and the bindgen target to run the BindGen program on the compiled code.

To try this out, open a console in the dwcode1 directory of the installed download and type ant compile bindgen. If you have Ant installed on your system and have installed the download code according to the instructions, you should see output similar to that shown in Figure 1:


Figure 1. Using the Ant build
Ant build output for generation from code

You can also run BindGen directly from the console. To do this, you need to include jibx-tools.jar in your Java classpath, along with the path for the compiled class files you'll use as input to the generation. If you want to duplicate the effect of the supplied Ant bindgen target, you also need to pass the root directory for the source files of your classes in the command line. Finally, you need to list the root class(es) you want used for generation. On UNIX® and Linux® systems, the Java command line (which consists of a single line, even if it appears as wrapped in your display) to duplicate the Ant bindgen target from a console in the dwcode1 directory (assuming you've followed the recommended installation instructions) is:

java -cp ../lib/jibx-tools.jar:bin org.jibx.binding.generator.BindGen 
   -s src org.jibx.starter.Order

On Windows, the command (a single line, regardless of its appearance here) is:

java -cp ..\lib\jibx-tools.jar;bin org.jibx.binding.generator.BindGen 
   -s src org.jibx.starter.Order

Many other options can be passed to BindGen from the command line. You'll look into those later in the tutorial. Right now, let's look at the generated schema.



Back to top


Generated artifacts

Listing 2 shows the generated schema output from BindGen (as starter.xsd), slightly reformatted to fit the page width and with some of the details removed. The start tag for the schema definition matching each Java class is displayed in bold to emphasize the structure.


Listing 2. Generated schema
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:tns="http://jibx.org/starter" elementFormDefault="qualified"
  targetNamespace="http://jibx.org/starter">
 <xs:complexType name="address">
  <xs:annotation>
   <xs:documentation>Address information.</xs:documentation>
  </xs:annotation>
  <xs:sequence>
   <xs:element type="xs:string" name="street1" minOccurs="0">
    <xs:annotation>
     <xs:documentation>First line of street information (required).</xs:documentation>
    </xs:annotation>
   </xs:element>
   ...
  </xs:sequence>
 </xs:complexType>
 <xs:element type="tns:order" name="order"/>
 <xs:complexType name="order">
  <xs:annotation>
   <xs:documentation>Order information.</xs:documentation>
  </xs:annotation>
  <xs:sequence>
   <xs:element name="customer" minOccurs="0">
    <xs:complexType>
     ...
    </xs:complexType>
   </xs:element>
   <xs:element type="tns:address" name="billTo" minOccurs="0">
    <xs:annotation>
     <xs:documentation>Billing address information.</xs:documentation>
    </xs:annotation>
   </xs:element>
   <xs:element name="shipping" minOccurs="0">
    <xs:simpleType>
     <xs:annotation>
      <xs:documentation>Supported shipment methods. The "INTERNATIONAL" shipment methods
        can only be used for orders with shipping addresses outside the U.S., and one of
        these methods is required in this case.</xs:documentation>
     </xs:annotation>
     <xs:restriction base="xs:string">
      <xs:enumeration value="STANDARD_MAIL"/>
      ...
     </xs:restriction>
    </xs:simpleType>
   </xs:element>
   <xs:element type="tns:address" name="shipTo" minOccurs="0">
    <xs:annotation>
     <xs:documentation>Shipping address information. If missing, the billing address is
       also used as the shipping address.</xs:documentation>
    </xs:annotation>
   </xs:element>
   <xs:element name="item" minOccurs="0" maxOccurs="unbounded">
    <xs:complexType>
     <xs:sequence>
      <xs:element type="xs:string" name="id" minOccurs="0">
       <xs:annotation>
        <xs:documentation>Stock identifier. This is expected to be 12 characters in
          length, with two leading alpha characters followed by ten decimal
          digits.</xs:documentation>
       </xs:annotation>
      </xs:element>
      <xs:element type="xs:string" name="description" minOccurs="0">
       <xs:annotation>
        <xs:documentation>Text description of item.</xs:documentation>
       </xs:annotation>
      </xs:element>
     </xs:sequence>
     <xs:attribute type="xs:int" use="required" name="quantity">
      <xs:annotation>
       <xs:documentation>Number of units ordered.</xs:documentation>
      </xs:annotation>
     </xs:attribute>
     <xs:attribute type="xs:float" use="required" name="price">
      <xs:annotation>
       <xs:documentation>Price per unit.</xs:documentation>
      </xs:annotation>
     </xs:attribute>
    </xs:complexType>
   </xs:element>
  </xs:sequence>
  <xs:attribute type="xs:long" use="required" name="orderNumber"/>
  <xs:attribute type="xs:date" name="orderDate">
   <xs:annotation>
    <xs:documentation>Date order was placed with server.</xs:documentation>
   </xs:annotation>
  </xs:attribute>
  <xs:attribute type="xs:date" name="shipDate">
   <xs:annotation>
    <xs:documentation>
     <![CDATA[Date order was shipped. This will be <code>null</code> if the order
       has not yet shipped.]]></xs:documentation>
   </xs:annotation>
  </xs:attribute>
 </xs:complexType>
</xs:schema>

By default, BindGen generates a schema with nested complexType and simpleType definitions for types that are used only once and separate definitions for types that are used more than once. In this case, the nested style results in a schema with just three global definitions: the address and order complex types, and the order element. The Address class is used in two places within the Order class (for billing and shipping addresses), which is why that class is represented by a separate global definition in the schema. (Schema allows you to reuse definitions only if they're global.) The other classes in the Java data structure (Customer, Item, and Shipping) are each referenced at only one point in the Order class, so the corresponding type definitions are embedded directly within the order schema type definition.

One of the nicer BindGen features is that it can generate schema documentation from Javadocs in the input classes. You can see the schema documentation in Listing 2 for each field with a Javadoc in Listing 1, and for each global type corresponding to a class with a Javadoc. Not all forms of Javadocs can be matched with schema components by BindGen's default handling — and some Javadocs, such as those on "get" access methods, may look odd when converted to schema documentation — but the resulting schema documentation can be extremely useful for clarifying the proper use of the XML representation. You can even define your own formatter class for Javadocs used as schema documentation, if you want to make some changes to the text in the process of conversion (such as stripping "Get the ..." lead sentences from "get" method Javadocs).

This Javadoc conversion feature works only if you have the source code available for the classes and provide an argument to BindGen telling it the root directory path (or paths). In the command-line samples I provided earlier (see Generating the default binding and schema), the source path is supplied as -s src.

Generated JiBX binding

Besides the schema definition, BindGen also produces a JiBX binding definition (as the binding.xml file, in this case) that tells the JiBX binding compiler how to convert between the Java classes and XML. That binding definition is actually the main output of BindGen, with the schema generated from the binding. Binding definitions contain full details of the conversions to be done by JiBX, so they're necessarily complex. Fortunately, you don't need to understand the binding definition in order to work with JiBX using BindGen binding and schema generation, so this tutorial doesn't cover the details.



Back to top



Go to the previous pagePage 3 of 11 Go to the next page