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 4 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


Working with XML documents

In this section, you'll learn about running the JiBX binding compiler and using JiBX at run time to work with XML documents.

Running the JiBX binding compiler

To use the generated binding definition in working with XML documents, you first need to run the JiBX binding compiler tool. The binding compiler adds bytecode to your compiled class files that actually implements the conversions to and from XML, as specified by the binding definition. You must run the binding compiler each time you recompile your Java classes or modify the binding definition, so it's generally best to add the binding compiler step as part of your project's standard build process.

The binding compiler is included in the JiBX distribution as part of jibx-bind.jar. The JiBX documentation provides full details about different ways to run the binding compiler, including how you can run it at run time rather than as part of the build. JiBX also provides plug-ins for Eclipse and IntelliJ IDEA that automatically run the binding compiler when you're working in these IDEs.

For this tutorial's purposes, you'll keep things simple and just run the binding compiler through Ant, using the build.xml's bind target. Figure 2 shows the output that you should see when you run this target, assuming you've already run the compile and bindgen targets. (You can also run all three targets in sequence by listing them in order on the command line: ant compile bindgen bind.)


Figure 2. Ant build bind task
Ant build output for binding compiler


Back to top


Using JiBX at run time

Listing 3 shows a simple test document matching the generated schema, included in the tutorial's code download as data.xml:


Listing 3. Default binding test document
<order orderNumber="12345678" orderDate="2008-10-18" shipDate="2008-10-22"
    xmlns="http://jibx.org/starter">
  <customer customerNumber="5678">
    <firstName>John</firstName>
    <lastName>Smith</lastName>
  </customer>
  <billTo>
    <street1>12345 Happy Lane</street1>
    <city>Plunk</city>
    <state>WA</state>
    <postCode>98059</postCode>
    <country>USA</country>
  </billTo>
  <shipping>PRIORITY_MAIL</shipping>
  <shipTo>
    <street1>333 River Avenue</street1>
    <city>Kirkland</city>
    <state>WA</state>
    <postCode>98034</postCode>
    <country>USA</country>
  </shipTo>
  <item quantity="1" price="5.99">
    <id>AC4983498512</id>
    <description>Left-handed widget</description>
  </item>
  <item quantity="2" price="9.50">
    <id>IW2349050499</id>
    <description>Right-handed widget</description>
  </item>
  <item quantity="1" price="8.95">
    <id>RC3000488209</id>
    <description>High-speed MP3 rewinder</description>
  </item>
</order>

The download package also includes a simple test program, shown here as Listing 4, that demonstrates using JiBX for both unmarshalling and marshalling documents. (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.) The Ant run target executes this test program, using the Listing 3 document as input and writing the marshalled copy of the document to a file named out.xml.


Listing 4. Test program
public class Test
{
    /**
     * Unmarshal the sample document from a file, compute and set order total, then
     * marshal it back out to another file.
     * 
     * @param args 
     */
    public static void main(String[] args) {
        if (args.length < 2) {
            System.out.println("Usage: java -cp ... " +
                "org.jibx.starter.Test in-file out-file");
            System.exit(0);
        }
        try {
            
            // unmarshal customer information from file
            IBindingFactory bfact = BindingDirectory.getFactory(Order.class);
            IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
            FileInputStream in = new FileInputStream(args[0]);
            Order order = (Order)uctx.unmarshalDocument(in, null);
            
            // compute the total amount of the order
            float total = 0.0f;
            for (Iterator<Item> iter = order.getItems().iterator(); iter.hasNext();) {
                Item item = iter.next();
                total += item.getPrice() * item.getQuantity();
            }
            order.setTotal(new Float(total));
            
            // marshal object back out to file (with nice indentation, as UTF-8)
            IMarshallingContext mctx = bfact.createMarshallingContext();
            mctx.setIndent(2);
            FileOutputStream out = new FileOutputStream(args[1]);
            mctx.setOutput(out, null);
            mctx.marshalDocument(order);
            System.out.println("Processed order with " +  order.getItems().size() +
                " items and total value " + total);
            
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            System.exit(1);
        } catch (JiBXException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
}

Figure 3 shows the output you should see when you run the run target:


Figure 3. Ant build run task
Ant build output from running test program

You can inspect the generated out.xml file to see how it matches the original input shown in Listing 3. Aside from namespace declaration and attribute order and the added total attribute in the output (computed and set by the test program), the two documents should be identical. This won't always be the case! JiBX, like most forms of data binding, works with only the "significant" data in the document, meaning those values being used by your application. Nonsignificant parts of the document (such as whitespace within a start or end tag, text between elements, and comments) are lost when you unmarshal a document. Part of the reason the input and output documents are so similar in this case is that the Listing 4 code sets the output format to use indentation of two spaces per element nesting level, matching the input document.

Sharp observers will notice one difference between the input and output that seems significant, in the item-list portion of the output document, shown in Listing 5:


Listing 5. Item list from output document
<item quantity="1" price="5.99">
    <id>AC4983498512</id>
    <description>Left-handed widget</description>
  </item>
  <item quantity="2" price="9.5">
    <id>IW2349050499</id>
    <description>Right-handed widget</description>
  </item>
  <item quantity="1" price="8.95">
    <id>RC3000488209</id>
    <description>High-speed MP3 rewinder</description>
  </item>

If you compare the line shown in bold in Listing 5 with the corresponding line in the Listing 3 original document, you can see that the price has changed from 9.50 to 9.5, with the trailing zero removed. This is not an error, though. The representation used for the price value is a float, and in terms of both Java and XML schema, leading zeros before the decimal point and trailing zeros after the decimal point are not significant for a float.



Back to top



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