Castor XML Tutorial
Document Sample


Page 1 of 13 Castor XML Binding Tutorial Ver 1.0
Castor XML Binding Tutorial
Date: 28 Jan 2005
Table of contents
1 Introduction ....................................................................................................................... 2
2 Overview ........................................................................................................................... 2
3 Binaries ............................................................................................................................. 2
4 Installation......................................................................................................................... 3
5 SourceGen Tool ................................................................................................................ 4
5.1 Usage......................................................................................................................... 4
5.2 Steps to generate code ............................................................................................... 4
6 Using generated code ........................................................................................................ 8
7 Compile And Build ......................................................................................................... 10
8 Custom Field Handler with binding................................................................................ 11
9 References ....................................................................................................................... 13
Page 2 of 13 Castor XML Binding Tutorial Ver 1.0
1 Introduction
This document is intended to explain the Castor XML-binding (SourceGen tool) in brief,
so that developer can understand the usage of Castor SourceGen in short time.
2 Overview
Castor is the Open Source data binding framework for Java. Mainly it consist of two
feature Castor XML and Castor JDO,
1. Castor XML - Java Object to and from XML-binding
A. XML – binding :
a) Source code from XML Schema can be generated for Java Objects using
SourceGen tool.
b) Provides easy way to un-marshal XML file to Java Object and marshal Java
Object to XML file.
c) Provides the way to customize the source code generation by means of
binding-file.
d) No need to use the DOM, SAX anymore.
B. XML – mapping :
a) Provides the way to map the existing Java Objects to XML file by means of
mapping-file.
b) Provides easy way to transform the Java Objects to XML file, vice versa.
2. Castor JDO - Java Object to and from DataBase-binding
Castor JDO provides the means to persist the Java Objects directly to DataBase. It
maps the Java Object to DataBase tables. One can avoid using JDBC API. Castor JDO
is similar technology like Sun’s JDO but they actually they are very different.
This tutorial explains about the XML – binding alone.
3 Binaries
Castor binaries are available at http://www.castor.org/download.html
Let’s download the latest version from,
ftp://ftp.exolab.org/pub/castor/castor_0.9.6/
Then, click and save castor-0.9.6-RC3.zip.
Page 3 of 13 Castor XML Binding Tutorial Ver 1.0
4 Installation
Unzip the zip file in some folder lets call this folder CASTOR_HOME.
We have to do some manual work before running the SourceGen tool,
1. Create “lib” folder under CASTOR_HOME, say CASTOR_HOME\lib.
2. Copy all “*.jar” files lying in CASTOR_HOME to CASTOR_HOME\lib.
3. Create “bin” folder under CASTOR_HOME, say CASTOR_HOME\bin.
4. Copy “SourceGen.bat” file lying in CASTOR_HOME to CASTOR_HOME\bin.
5. Modify the SourceGen.bat as shown below, (modified part is shown in bold letters)
SourceGen.bat
set CASTOR_HOME= D:\castor-0.9.6-RC3
set JAVA_HOME=D:\jdk142_04
set JAVA=%JAVA_HOME%\bin\java
set cp=%CLASSPATH%
for %%i in (%CASTOR_HOME%\lib\*.jar) do call cp.bat %%i
set cp=%cp%;.
%JAVA% -classpath %CP%
org.exolab.castor.builder.SourceGenerator %1 %2 %3 %4 %5 %6 %7 %8 %9
6. Create the “cp.bat” file in CASTOR_HOME\bin with following line,
cp.bat
set CP=%CP%;%1
7. External library on which Castor is dependent is comes with Castor source
distribution, either you can download the Castor Source distribution OR download the
following dependent library from respective website.
8. Castor is depending on following external library,
A. Xerces and Apache serializer shipped with Xerces.
Site http://xml.apache.org/dist/xerces-j/
download Xerces-J-tools.2.5.0.zip from the above site and then copy -
xercesImpl.jar and xml-apis.jar file from zip to CASTOR_HOME\lib.
B. Jakarta ORO
Site http://jakarta.apache.org/site/binindex.cgi#oro
download jakarta-oro-2.0.8.zip from the above site and then copy -
jakarta-oro-2.0.8.jar file from zip to CASTOR_HOME\lib.
C. Jakarta Regexp (Is shipped with Jakarta ORO.)
Page 4 of 13 Castor XML Binding Tutorial Ver 1.0
D. Jakarta Common-Logging
Site http://jakarta.apache.org/site/binindex.cgi#commons-logging
download commons-logging-1.0.4.zip from the above site and then copy -
commons-logging.jar file from zip to CASTOR_HOME\lib.
9. SourceGen tool requires following jars in lib directory,
1. castor-0.9.6-RC3-xml.jar
2. castor-0.9.6-RC3.jar
3. commons-logging.jar
4. jakarta-oro-2.0.8.jar
5. xercesImpl.jar
5 SourceGen Tool
Xml Schema SourceGen Java Classes
Input Output
5.1 Usage
SourceGen -i xsdfilename [-package package-name] [-dest dest-dir]
[-line-separator ( unix | mac | win)] [-f ] [-h ] [-verbose ] [-nodesc ]
[-types types] [-type-factory classname] [-nomarshall ] [-testable ]
[-sax1 ] [-binding-file filename] [-generateImportedSchemas ]
Do not bother about all options of command. We require very few to start with.
Let’s get into process. Let’s generate source code from XML Schema using SourceGen
tool. Let’s create some directories for execution of SourceGen tool.
5.2 Steps to generate code
1. Please create the following directories,
A. CASTOR_HOME\samples
B. CASTOR_HOME\samples\src
C. CASTOR_HOME\samples\classes
D. CASTOR_HOME\samples\schema
E. CASTOR_HOME\samples\xml
2. Create the PurchaseOrder.xsd from the following content and place the file under
CASTOR_HOME\samples\schema. This PurchaseOrder contains the date, customer, line
items and shipper child elements. Please refer PurchaseOrder.xsd shown below,
PurchaseOrder.xml is also sown for more clarity.
3. Then execute the command,
castor_home\bin>SourceGen -i castor_home\samples\schema\purchaseorder.xsd
-dest castor_home\samples\src
Page 5 of 13 Castor XML Binding Tutorial Ver 1.0
PurchaseOrder.xsd PurchaseOrder.xml
<xs:schema <?xml version="1.0" encoding="UTF-8"?>
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:po="http://openuri.org/easypo" <po:purchase-order
targetNamespace="http://openuri.org/easypo"
elementFormDefault="qualified"> xmlns:po="http://org.openuri/easypo"
xmlns="http://openuri.org/easypo"
<xs:element name="purchase-order"> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<xs:complexType> xsi:schemaLocation="http://org.openuri/easypo easypo.xsd">
<xs:sequence>
<xs:element name="date" type="xs:dateTime"/> <date>21/12/2004 18:04:14</date>
<xs:element name="customer" type="po:customer"/>
<xs:element name="line-item" type="po:line-item" minOccurs="0" <customer age="70">
maxOccurs="unbounded"/> <name>Mani Ayam</name>
<xs:element name="shipper" type="po:shipper" minOccurs="0" <address>Tokyo Japan</address>
maxOccurs="1"/> </customer>
</xs:sequence>
</xs:complexType> <line-item>
</xs:element> <description>EJB2.0 Book</description>
<price>120.0</price>
<xs:complexType name="customer"> <quantity>100</quantity>
<xs:sequence> </line-item>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/> <line-item>
</xs:sequence> <description>JSP2.3 Book</description>
<xs:attribute name="age" type="xs:int"/> <price>230.0</price>
<xs:attribute name="moo" type="xs:int" default="100"/> <quantity>84</quantity>
<xs:attribute name="poo" type="xs:int" fixed="200"/> </line-item>
</xs:complexType>
<line-item>
<xs:complexType name="line-item"> <description>JAVA2.0 Book</description>
<xs:sequence> <price>130.0</price>
<xs:element name="description" type="xs:string"/> <quantity>50</quantity>
<xs:element name="price" type="xs:decimal"/> </line-item>
<xs:element name="quantity" type="xs:integer"/>
</xs:sequence> <shipper>
</xs:complexType> <name>Suraksha</name>
<per-kg-rate>23.0</per-ounce-rate>
<xs:complexType name="shipper"> </shipper>
<xs:sequence>
<xs:element name="name" type="xs:string"/> </po:purchase-order>
<xs:element name="per-kg-rate" type="xs:decimal"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Then you will see some warning like below,
Warning: A class name generation conflict has occured between complexType
'complexType:customer' and element '/purchase-order/customer'. Please use a Binding
file to solve this problem.Continue anyway [not recommended] (y|n|?)
4. Just abort the process by CTL+C. We need to do something more. This warning is
generated because '/purchase-order/customer' element name and
'complexType:customer' type name are same, Castor can not create two classes with
same name. Similarly if you notice “line-item” and “shipper” element name and type
name are same. So it is naming conflict for Castor.
Page 6 of 13 Castor XML Binding Tutorial Ver 1.0
5. We will have to customize the generated class names for either types or elements to
avoid the naming conflict. It is possible with binding xml file. Create the -bindingpo.xml
with the following content and place the same in CASTOR_HOME\samples\schema folder.
bindingpo.xml
<?xml version="1.0"?>
<cbf:binding xmlns:cbf="http://www.castor.org/SourceGenerator/Binding"
defaultBindingType='element'>
<!-- avoid name collisions -->
<cbf:complexTypeBinding name="customer">
<cbf:java-class name="CustomerType"/>
</cbf:complexTypeBinding >
<cbf:complexTypeBinding name="line-item">
<cbf:java-class name="LineItemType"/>
</cbf:complexTypeBinding >
<cbf:complexTypeBinding name="shipper">
<cbf:java-class name="ShipperType"/>
</cbf:complexTypeBinding >
</cbf:binding>
You might have understood that if we keep the Element name and Type name different
in schema we need not do this overwork. But better to know how to do it!!
6. Now execute the sourceGen command with one additional option as shown below,
castor_home\bin>SourceGen -i castor_home\samples\schema\purchaseorder.xsd
-dest castor_home\samples\src
–binding-file castor_home\samples\schema\bindingpo.xml
7. You will see the source code is generated under castor_home\samples\src. We can
add the package in the source by using –package option in SourceGen command line Or
adding following element in bindingpo.xml, Please do either one step to add the package
name. Let’s add “org.openuri.easypo” package name. Please delete the generated code
from castor_home\samples\src first.
<?xml version="1.0"?>
<cbf:binding xmlns:cbf="http://www.castor.org/SourceGenerator/Binding"
defaultBindingType='element'>
<!--define the {namespace,package} binding -->
<cbf:package>
<cbf:name>org.openuri.easypo</cbf:name>
<cbf:namespace>http://openuri.org/easypo</cbf:namespace>
</cbf:package>
…
</cbf:binding>
8. Now please refer the generated code e.g. PurchaseOrder.java. This is the Java Class
generated for <purchase-order> element. It has got the setter and getter methods for
<date>, <customer>, <line-item> and <shipper> elements as shown below,
A. setDate(..), getDate()
B. setCustomer(..), getCustomer()
C. setShipper(..), getShipper()
D. addLineItem(..), getLineItem()
Page 7 of 13 Castor XML Binding Tutorial Ver 1.0
And some additional methods like marshal(..) and unmarshal(..).marshal(..) and
unmarshal(..) methods can be used to write the data in Object to xml file and read the
data from the xml file to Object. That’s all. Its great na!!
9. If you notice <price> element of <line-item> and <per-kg-rate> element of
<shipper> are generated as java type java.math.BigDecimal. Please refer
LineItemType.java and ShipperType.java, We may not want to use BigDecimal in our
application. We can change this default behavior and can customize the java type to
prime type “double” by specifying same in binding file. Please change the bindingpo.xml
as shown below, and generate the code again.
bindingpo.xml
<?xml version="1.0"?>
<cbf:binding xmlns:cbf="http://www.castor.org/SourceGenerator/Binding"
defaultBindingType='element'>
<!--define the {namespace,package} binding -->
<cbf:package>
<cbf:name>org.openuri.easypo</cbf:name>
<cbf:namespace>http://openuri.org/easypo</cbf:namespace>
</cbf:package>
<!-- avoid name collisions -->
<cbf:complexTypeBinding name="customer">
<cbf:java-class name="CustomerType"/>
</cbf:complexTypeBinding >
<cbf:complexTypeBinding name="line-item">
<cbf:java-class name="LineItemType"/>
<cbf:elementBinding name='price'>
<cbf:member name="price" java-type="double"/>
</cbf:elementBinding>
</cbf:complexTypeBinding >
<cbf:complexTypeBinding name="shipper">
<cbf:java-class name="ShipperType"/>
<cbf:elementBinding name='per-kg-rate'>
<cbf:member java-type="double"/>
</cbf:elementBinding>
</cbf:complexTypeBinding >
</cbf:binding>
10. Now you can see the price in LineItemType.java and perKgRate in ShipperType.java
has changed to double.
Tip: More details on binding file can be find at,
http://castor.exolab.org/sourcegen.html#Binding-File
Schema for binding file available at,
http://castor.exolab.org/binding.xsd
OR
castor_home\doc\binding.xsd
Page 8 of 13 Castor XML Binding Tutorial Ver 1.0
6 Using generated code
1. Now let’s write the code to create new PurchaseOrder.xml using the generated code
and code to read the PurchaseOrder.xml.
Please create the POCreator.java and POReader.java with below content and place the
same in castor_home\samples\src directory.
POReader.java
import org.exolab.castor.xml.Unmarshaller;
import java.io.*;
import org.openuri.easypo.*;
public class POReader {
public static void main(String[] args) {
try {
System.out.println("Unmarshalling PurchaseOrder");
PurchaseOrder po = null;
po = (PurchaseOrder)PurchaseOrder.unmarshal(new FileReader("xml/PurchaseOrder.xml"));
StringWriter sw = new StringWriter();
po.marshal(sw);
System.out.println(sw.toString());
} catch (Exception e) {
e.printStackTrace();
}
} //end of main()
} //end of class POReader
Page 9 of 13 Castor XML Binding Tutorial Ver 1.0
POCreator.java
import org.exolab.castor.xml.Marshaller;
import org.exolab.castor.util.LocalConfiguration;
import java.io.*;
import java.util.*;
import org.openuri.easypo.*;
public class POCreator
{
public static void main(String[] args)
{
try
{
//following code populates the PurchaseOrder Object
PurchaseOrder po = new PurchaseOrder();
po.setDate(new Date());
po.setCustomer(getCustomer("Mani Ayam","Tokyo Japan",70));
po.addLineItem(getLineItem("EJB2.0 Book",120D,100));
po.addLineItem(getLineItem("JSP2.3 Book",230D,84));
po.addLineItem(getLineItem("JAVA2.0 Book",130D,50));
po.setShipper(getShipper("Suraksha",23D));
//following code sets property to true to get the properly indented XML
Properties prop = LocalConfiguration.getInstance().getProperties();
prop.setProperty("org.exolab.castor.indent","true");
//following code transforms the Java Object into XML
Marshaller marshaller = new Marshaller(new FileWriter("xml/PurchaseOrder.xml"));
marshaller.setNamespaceMapping("po","http://org.openuri/easypo");
marshaller.setSchemaLocation("http://org.openuri/easypo easypo.xsd");
marshaller.setValidation(true);
marshaller.setRootElement("po:purchase-order");
marshaller.marshal(po);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Program Over...");
} //end of main()
private static Customer getCustomer(String name, String address,int age)
{
Customer cust = new Customer();
cust.setName(name);
cust.setAddress(address);
cust.setAge(age);
return cust;
}//end of getCustomer()
private static LineItem getLineItem(String itemDescription, double itemPrice, int itemQuantity)
{
LineItem newItem = new LineItem();
newItem.setDescription(itemDescription);
newItem.setPrice(itemPrice);
newItem.setQuantity(itemQuantity);
return newItem;
} //end of getLineItem()
private static Shipper getShipper(String name, double perKgRate)
{
Shipper shiper = new Shipper();
shiper.setName(name);
shiper.setPerKgRate(perKgRate);
return shiper;
} // end of getShipper()
} //end of class POCreator
Page 10 of 13 Castor XML Binding Tutorial Ver 1.0
7 Compile And Build
Now let’s compile the generated source and our source and execute.
1. Please create the build.bat file under castor_home\samples folder to set the
environment, compile and execute the code, from the below content,
build.bat
echo off
set CASTOR_HOME=D:\castor-0.9.6-RC3
set JAVA_HOME=D:\jdk142_04
set CLASSPATH=%CASTOR_HOME%\lib\castor-0.9.6-RC3-xml.jar
set CLASSPATH=%CLASSPATH%;%CASTOR_HOME%\lib\commons-logging.jar
set CLASSPATH=%CLASSPATH%;%CASTOR_HOME%\lib\xercesImpl.jar
set CLASSPATH=%CLASSPATH%;%CASTOR_HOME%\samples\classes;.;
javac –d %CASTOR_HOME%\samples\classes %CASTOR_HOME%\samples\src\*.java
%CASTOR_HOME%\samples\src\org\openuri\easypo\*.java
java POCreator
java POReader
2. castor-0.9.6-RC3-xml.jar is required for compiling the generated code, and others are
required to execute the code.
3. You can see the PurchaseOrder.xml is created under castor_home\samples\xml.
Castor configuration can also be set from castor.properties file. This file must be
available in classpath.
e.g, castor.properties file
#if set true generated xml file will be well formated
org.exolab.castor.indent=true
#if set to true XML will be validated during marshalling and un-marshaling
org.exolab.castor.validation=true
#if set true debug mode is enabled
org.exolab.castor.debug=false
Tip: For more details, please refer castor.properties present in castor-0.9.6-
RC3-xml.jar.
Page 11 of 13 Castor XML Binding Tutorial Ver 1.0
8 Custom Field Handler with binding
Many times we need to handle the field value before get OR set methods. Let’s see how
it can be done with Castor.
1. Our task is to put the formatted date in XML file. I guess you might not have liked the
format of date in PurchaseOrder.xml in above example. So lets try to change the same
in “"yyyy/MM/dd HH:mm:ss"” format.
For this we need do write the Class which implements interface
“org.exolab.castor.mapping.FieldHandler”.
2. Please add the following content in binding file.
bindingpo.xml
<?xml version="1.0"?>
<cbf:binding xmlns:cbf="http://www.castor.org/SourceGenerator/Binding"
defaultBindingType='element'>
<!--define the {namespace,package} binding -->
…
<!--define the custome field handler binding -->
<cbf:elementBinding name="purchase-order">
<cbf:java-class name="PurchaseOrder"/>
<cbf:elementBinding name="date">
<cbf:member name="date" handler="org.openuri.easypo.PODateHandler"/>
</cbf:elementBinding>
</cbf:elementBinding>
<!-- avoid name collisions -->
…
</cbf:binding>
3. Please create PODateHandler.java file from below content. Place the same in
castor_home\samples\src fodler.
Page 12 of 13 Castor XML Binding Tutorial Ver 1.0
package org.openuri.easypo;
import org.exolab.castor.mapping.FieldHandler;
import org.exolab.castor.mapping.ValidityException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class PODateHandler implements FieldHandler
{
private static final String FORMAT = "yyyy/MM/dd HH:mm:ss";
public PODateHandler() {
super();
}//end of PODateHandler()
public Object getValue( Object object )
throws IllegalStateException
{
PurchaseOrder root = (PurchaseOrder)object;
Date value = root.getDate();
if (value == null) return null;
SimpleDateFormat formatter = new SimpleDateFormat(FORMAT);
Date date = (Date)value;
return formatter.format(date);
} //end of getValue()
public void setValue( Object object, Object value )
throws IllegalStateException, IllegalArgumentException
{
PurchaseOrder root = (PurchaseOrder)object;
SimpleDateFormat formatter = new SimpleDateFormat(FORMAT);
Date date = null;
try {
date = formatter.parse((String)value);
}
catch(ParseException px) {
throw new IllegalArgumentException(px.getMessage());
}
root.setDate(date);
}//end of setValue()
//just add the below methods without botheration, they are present in interface.
public Object newInstance( Object parent )
throws IllegalStateException
{
//-- Since it's marked as a string...just return null,
//-- it's not needed.
return null;
}//end of newInstance()
public void resetValue( Object object )
throws IllegalStateException, IllegalArgumentException
{
((PurchaseOrder)object).setDate(null);
}//end of resetValue()
/** @deprecated No longer supported */
public void checkValidity( Object object )
throws ValidityException, IllegalStateException
{
// do nothing
}//end of checkValidity
}//end generate the
Pleaseof PODateHandler() source code again to make get effect of PODateHandler.
Page 13 of 13 Castor XML Binding Tutorial Ver 1.0
4. Please run the build.cmd to compile and execute the code.
5. You can see the date has been input in new format. Castor by default generates the
attribute xsi:types=”java.lang.String” for this date element. We have to live with this as
of now. If we remove the same, We can not execute the POReader. Keep this in mind.
Now come on explore more on your own.
A. Castor provides the ANT TASK to generate the source from schema, try using. I
am sorry I did not try it.
B. I guess GeneralizedFieldHandler is not supported for binding file. I tried. Please
refer link B. below.
9 References
A. http://castor.exolab.org/
B. http://castor.exolab.org/xml-fieldhandlers.html
---------------------------XXXX END OF DOCUMENT XXXX---------------------------
Related docs
Get documents about "