Java Tutorial - Java Scipt : Castor Test

Java Tutorial - Java Scipt :

Castor Test

We’ll be working with order.xml again, but this time we’re going to put a different spin on things. Castor allows us \ to create Java object bindings to the XML document, in this case order.xml. Now instead of dealing with objects
that model XML documents, we can work directly with the Order object. Likewise,changing attributes is now done via mutator methods on the LineItem object. Basically, with Castor, first class objects can be generated to and from data in the XML documents. The easiest way to see how this works is to check out the code example.

Installation

Before installing Castor, please download and install Xerces Java 2 from the Apache XML site (http://xml.apache.org/xerces2-j/index.html). You’ll need to download version 2.3 or above. The binaries are all that we need for the example. Once the archive is downloaded, extract the files into the directory where you want to house Xerces. Then, set the XERCES_HOME environment variable to point to this directory. On a Windows system, you can install it into a directory such as c:\java\xerces2. On Linux, you could use /usr/local/xerces2. The latest Castor release can be downloaded from the project’s Web site (http://castor.exolab.org). You can download either the .jar file or a full distribution. For this example, we’ll only need the Castor XML .jar file, which is castor 0.9.42-xml.jar as of the time of writing. Be sure to copy this .jar file to the directory where you’re going to put the Castor example.




Code Examples

The first feature we’ll want to check out in Castor is the automated mapping. In the code example, we’re going to use that with the order object. Then, we’ll show how to use a custom-mapping file to create a binding with the order.xml file we’ve been using in the other examples.
Here’s the order.java source code:

import java.io.*;
import java.util.*;
public class Order implements Serializable
{
private ArrayList moLineItems = new ArrayList();
private String msNotes;
public void setNotes( String sNotes )
{
msNotes = sNotes;
}
public String getNotes()
{
Adding XML Power Tools 457
return msNotes;
}
public ArrayList getLineItems()
{
return moLineItems;
}
public void setLineItems( ArrayList oLineItems )
{
moLineItems = oLineItems;
}
public void addLineItem( LineItem oLineItem )
{
getLineItems().add( oLineItem );
}
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append( “Order Notes: “ )
.append( getNotes() )
.append( “\nLine Items: “ );
Iterator itr = getLineItems().iterator();
while( itr.hasNext() )
{
sb.append( itr.next().toString() );
}
return sb.toString();
}
}

Each order can have one or more line items. The source code to implement the LineItem class is:

import java.io.*;
public class LineItem implements Serializable
{
private String msName;
private String msColor;
private String msSize;
private int miCount;
458 Chapter 12
public LineItem()
{}
public LineItem(
String sName,
int iCount,
String sColor,
String sSize )
{
setName( sName );
setCount( iCount );
setColor( sColor );
setSize( sSize );
}
public void setName( String sName )
{
msName = sName;
}
public void setCount( int iCount )
{
miCount = iCount;
}
public void setColor( String sColor )
{
msColor = sColor;
}
public void setSize( String sSize )
{
msSize = sSize;
}
public String getName()
{
return msName;
}
public int getCount()
{
Adding XML Power Tools 459
return miCount;
}
public String getColor()
{
return msColor;
}
public String getSize()
{
return msSize;
}
public String toString()
{
return “\nLine Item “ + getName() +
“ “ + getCount() +
“ “ + getColor() +
“ “ + getSize();
}
}

Now, we’ll look at the test program that will generate a simple order and use the XML binding to persist it to and from disk. This example relies on the automated binding. Castor will inspect the Java object and generate a binding based on the accessor methods (those starting with get*). Note that in order for the automated binding to work, Castor must have access to concrete classes with an empty public constructor. These restrictions are quite reasonable and are the same as required by Java Beans.
Here’s the source for test_castor.java:

import java.io.*;
import org.exolab.castor.mapping.*;
import org.exolab.castor.xml.*;
public class castor_test
{
public static void main( String args[] )
{
// --- Creating the order object ---
Order oOrder = new Order();
oOrder.setNotes( “This is just a test order.” );
oOrder.addLineItem( new LineItem( “T-shirt”, 2, “red”, “M” ) );
460 Chapter 12
oOrder.addLineItem( new LineItem( “T-shirt”, 1, “blue”, “S” ) );
System.out.println( “After construction: “ + oOrder );
// --- Write out to disk. ---
Mapping oMapping = new Mapping();
// The above will be used for explicit mapping.
try
{
//NOTE: Uncomment the next line to use a custom mapping file.
//oMapping.loadMapping( “mapping.xml” );
Marshaller oMarshaller = new Marshaller(
new FileWriter( “order.xml” ) );
//NOTE: Uncomment the next line to use a custom mapping file.
//oMarshaller.setMapping( oMapping );
oMarshaller.marshal( oOrder );
}
catch( Exception e )
{
e.printStackTrace();
}
// --- Read back the object. ---
oOrder = null;
Unmarshaller oUnmarshaller = new Unmarshaller( Order.class );
try
{
//NOTE: Uncomment the next line to use a custom mapping file.
//oUnmarshaller.setMapping( oMapping );
oOrder = (Order) oUnmarshaller.unmarshal(
new FileReader( “order.xml” ) );
}
catch( Exception e )
{
e.printStackTrace();
}
System.out.println( “After unmarshalling: “ + oOrder );
}
}

To compile the program in Windows, use the following command:

javac -classpath .;castor-0.9.4.3-xml.jar castor_test.java Order.java LineItem.java

On Linux, the compile command is:

javac -classpath .:castor-0.9.4.3-xml.jar castor_test.java Order.java LineItem.java

This may be different depending on the version of the Castor jar you downloaded.
To run the example on Windows, use:

java -classpath .;castor-0.9.4.3-xml.jar;%XERCES_HOME%\xercesImpl.jar castor_test

On Linux, the command is:

java -classpath .:castor-0.9.4.3-xml.jar:$XERCES_HOME/xercesImpl.jar castor_test

 Make sure you have installed Xerces because Castor depends on it to run. Running the example will show that the automated binding does work, but an examination of the order.xml file that is generated shows that the format is not the same as that we’ve seen in previous examples. By using a custom mapping file, we can fix that Here’s the order.xml that is autogenerated, reformatted for readability:

<?xml version=”1.0” encoding=”UTF-8”?>
<order>
<notes>This is just a test order.</notes>
<line-items count=”2”
xsi:type=”java:LineItem”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>
<color>red</color>
<name>T-shirt</name>
<size>M</size>
</line-items>
<line-items count=”1”
xsi:type=”java:LineItem”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>
<color>blue</color>
<name>T-shirt</name>
<size>S</size>
</line-items>
</order>

To specify a mapping file, uncomment the lines that specify the mapping. These are the three lines preceded by a note comment in test_castor.java. Now, we need to write the mapping.xml file and save that in the same directory.
Here’s the source for mapping.xml:

<?xml version=”1.0”?>
<!DOCTYPE mapping PUBLIC
“-//EXOLAB/Castor Object Mapping DTD Version 1.0//EN”
“http://castor.exolab.org/mapping.dtd”>
<mapping>
<class name=”Order”>
<map-to xml=”order” />
<field name=”Notes”
type=”java.lang.String”>
<bind-xml name=”notes”
node=”attribute” />
</field>
<field name=”LineItems”
type=”LineItem”
collection=”arraylist”>
<bind-xml name=”line-item” node=”element” />
</field>
</class>
<class name=”LineItem”>
<field name=”Name” type=”java.lang.String”>
<bind-xml name=”name”
node=”attribute” />
</field>
<field name=”Count” type=”integer”>
<bind-xml name=”count”
node=”attribute” />
</field>
<field name=”Color” type=”java.lang.String”>
<bind-xml name=”color”
node=”attribute” />
</field>
<field name=”Size” type=”java.lang.String”>
<bind-xml name=”size”
node=”attribute” />
</field>
</class>
</mapping>

Run the Castor example again to try out the manual mapping. Not much is different judging from the output. However, if you look at the order.xml file in a text viewer, you’ll see that it is now clean of the metadata that Castor generates for the automated mappings. That same metadata is now explicitlycoded within binding rules in the mapping.xml file.

As you can see, Castor introduces a totally different way to work with XML documents. Bound Java objects are a far more natural way to work with XML. Castor is very handy for generating Java objects from existing XML data. Actually, Castor is primarily a binding tool, and it can be used to bind Java objects with other sources, most notably relational databases. The ability to map to existing XML documents is especially handy!