Example 15-9. Binding schema for the catalog document
<?xml version="1.0"?>
<xml-java-binding-schema version="1.0ea">
<element name="catalog" type="class" root="true" />
</xml-java-binding-schema>
This specifies the document as a binding schema, and defines the root
element. Save this file as catalog.xjc.
With a DTD (catalog.dtd from the last section on
Zeus) and a binding schema, you're ready to generate Java
classes. Execute the following command:
xjc c:\javaxml2\ch14\xml\jaxb\catalog.dtd c:\javaxml2\ch14\xml\jaxb\catalog.xjc
Or, on Unix or Cygwin:
xjc /javaxml2/ch14/xml/jaxb/catalog.dtd /javaxml2/ch14/xml/jaxb/catalog.xjc
Once that command completes, you get two classes in your current
directory, Catalog.java and
Item.java. These have the typical
set of methods you would expect:
public class Item {
public String getLevel( );
public void setLevel( );
public String getId( );
public void setId(String id);
public List getGuest( );
public void deleteGuest( );
public void emptyGuest( );
// And so on...
}
Note how JAXB deals with lists. It's a step up from Castor (in
my opinion), as it does provide access to the List
of guests. However (also my opinion), it lacks the convenience of an
addGuest( ) method that Zeus provides.
You'll need to handle all list manipulation by getting the list
and working on it directly:
// The Zeus way
item.addGuest(new Guest("Bela Bleck"));
// The JAXB way
List guests = item.getGuest( );
guests.add("Bela Fleck");
The generated classes are also all concrete classes, much like the
model that Castor uses.
The binding schema does provide some nifty options (even if
it's not XML). First, you can specify the package that
generated classes should be in; this is done using the
options element, with the
package attribute. Add this line to your binding
schema:
<?xml version="1.0"?>
<xml-java-binding-schema version="1.0ea">
<options package="javaxml2.jaxb" />
<element name="catalog" type="class" root="true" />
</xml-java-binding-schema>
Now, generated source will be placed in the javaxml2/jaxb directory with the same
structure as the package hierarchy. Next, let's specify that
the level attribute on the item
element should be a number (instead of the default, a
String):
<?xml version="1.0"?>
<xml-java-binding-schema version="1.0ea">
<options package="javaxml2.jaxb" />
<element name="catalog" type="class" root="true" />
<element name="item" type="class">
<attribute name="level" convert="int" />
</element>
</xml-java-binding-schema>
As you can see, I first added an element declaration for the
item element. This allows me to reference its
level attribute using the
attribute construct. To handle the datatype, I
specified the type I wanted (int) with the
convert attribute.
Continuing with the options that a binding schema supplies,
here's a really nice feature. You can actually change the name
of a property from what it is in the DTD. For example, I hate methods
like getId( ). Instead, I really prefer
getID( ), which looks much better. So, what I
really want is to name the id property from my DTD
as ID in Java. This turns out to be simple with
JAXB:
<?xml version="1.0"?>
<xml-java-binding-schema version="1.0ea">
<options package="javaxml2.jaxb" />
<element name="catalog" type="class" root="true" />
<element name="item" type="class">
<attribute name="level" convert="int" />
<attribute name="id" property="ID" />
</element>
</xml-java-binding-schema>
Once you've made all of these various changes, run the schema
compiler (xjc) again.
You'll get the modified classes I've been talking about,
and now can compile those:
javac -d . javaxml2/jaxb/*.java
If you have any problems, ensure that you still have jaxb-rt-1.0-ea.jar in your classpath.
There are quite a few more options for the binding schema than those
discussed here; in fact, many of these were undocumented, and I found
them by looking at the xjc.dtd
included with JAXB. I suggest you do the same, in addition to reading
the supplied documentation. Once you've got your classes
generated, it's on to marshalling and unmarshalling.