Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Practical data binding: JaxMe - The new kid on the block

Generating classes using JaxMe

Brett McLaughlin (brett@oreilly.com), Editor, O'Reilly and Associates
Brett McLaughlin has been working in computers since the Logo days. (Remember the little triangle?) He currently specializes in building application infrastructure using Java-related technologies. He has spent the last several years implementing these infrastructures at Nextel Communications and Allegiance Telecom, Inc. Brett is one of the co-founders of the Java Apache project Turbine, which builds a reusable component architecture for Web application development using Java servlets. He is also a contributor to the EJBoss project, an open source EJB application server, and Cocoon, an open source XML Web-publishing engine.

Summary:  The previous installments of this column gave you a thorough overview of JAXB, so you're now ready to study varying data binding implementations. This article begins an in-depth look at JaxMe, an open source implementation of JAXB. In addition to offering several enhancements to the basic JAXB specification, JaxMe offers integration with databases and Enterprise JavaBeans, both significant extensions to basic data binding behavior. Share your thoughts on this article with the author and other readers in the "XML and Java technology" discussion forum. (You can also click Discuss at the top or bottom of the article to access the forum.)

View more content in this series

Date:  09 Jul 2004
Level:  Introductory

Activity:  7732 views
Comments:  

It's no secret that Sun's JAXB, the Java API for XML, has had its fair share of criticism. In its earliest iteration (beta something-or-other), it was based on DTDs, and didn't support W3C XML Schema at all. It sat in that state for over a year, and then suddenly a 1.0 version was released. While that version addressed the schema support, it dropped DTDs completely, and all the code that developers had written (admittedly to beta software) suddenly stopped working. In more recent days, JAXB has picked up some support, but it still remains a very closed environment, with plenty of bugginess in the darker corners of the implementation.

In this article, I'll introduce the JaxMe project, which keeps most of JAXB's good features, and dumps many of its problems. First and foremost, though, JaxMe is open source (and under the Apache umbrella), which means that even if it disappeared today, developers could freely use and even modify its source code -- ensuring that code depending on it will happily go on running. If this alone isn't enough, JaxMe offers database interaction, support for Enterprise JavaBeans, and all sorts of other goodies.

To get you started, I'll walk you through class generation in JaxMe. While this is pretty basic stuff, it should get you familiar enough with JaxMe to look at some of its more interesting features.

Basic setup

Setting up JaxMe is a piece of cake. Visit the JaxMe project site (see Resources for links) and download the binaries from one of the Apache mirrors. As of this writing, the file I downloaded was incubated-jaxme-0.2-bin.tar.gz. (The 0.3 version became available shortly before this went to press; the instructions are the same, but the filename is incubated-jaxme-0.3-bin.tar.gz). Extract this to your development machine. While you can work with JaxMe on the command line, it's a pain (lots of JAR files) -- this article uses Ant to handle JaxMe tasks. You're strongly encouraged to do the same, and all the relevant Ant files are included here, easily modifiable for your own use.


Class generation

As with JAXB, you'll need some XML before you can do much of anything with JaxMe. Listing 1 shows a very simple XML schema that defines a student. Obviously, this leaves a lot to be desired, but I've kept things simple so you can focus on JaxMe rather than on schema semantics.


Listing 1. Simple student schema
<?xml version="1.0" encoding="UTF-8"?>

<schema
    xmlns="http://www.w3.org/2001/XMLSchema"
    xml:lang="EN"
    targetNamespace="http://dw.ibm.com/jaxme/student"
    xmlns:stu="http://dw.ibm.com/jaxme/student"
    elementFormDefault="qualified"
    attributeFormDefault="unqualified"
>

  <element name="Student">
    <complexType>
      <sequence>
        <element name="firstName" type="string" />
        <element name="lastName" type="string" />
        <element name="address" type="stu:Address" />
      </sequence>
    </complexType>
  </element>

  <complexType name="Address">
    <sequence>
      <element name="name" type="string"/>
      <element name="street" type="string"/>
      <element name="city" type="string"/>
      <element name="state" type="string"/>
      <element name="zip" type="positiveInteger"/>
   </sequence>
 </complexType>
 
 <complexType name="College">
   <sequence>
     <element name="name" type="string" />
     <element name="address" type="stu:Address" />
   </sequence>
 </complexType>

</schema>

If you've got your Ant build process set up correctly (described in detail at the end of this article), you can just type ant generate to create classes from this schema. I've left these details for the end of the article so that you can focus on JaxMe and its semantics throughout the article, and then look at all the Ant specifics later on. I'd actually recommend you read through the article once, and then work through the code, piece by piece. That way, you'll have the concepts down by the time you're actually entering code, and can probably troubleshoot any problems much more quickly.

Package specification

All of your generated classes will be placed in the package specified in the targetNamespace attribute. This convention is unique to JaxMe, so you'd do well to understand how it works. Look at the URI provided as an argument to this attribute: http://dw.ibm.com/jaxme/student. This is turned into a package name by the JaxMe schema compiler. First, "http://" is dropped. Then, the host name portion of the URI (in this case, "dw.ibm.com") is actually reversed -- resulting in "com.ibm.dw". That may seem a little odd, but it's actually the typical mechanism for packaging, and should make sense to those of you who are used to developing site-specific classes or beans, particularly tag libraries.

Finally, the remainder of the URI is split on the slash character (/) and appended to the base package that's derived from the host name. So the complete package for the schema in Listing 1 turns out to be com.ibm.dw.jaxme.student. All classes generated from this schema are dropped into this package.

XML semantics

In addition to providing information to JaxMe, the targetNamespace attribute has some XML-specific implications. It tells the schema processor to put all constructs created (like the Address complex type) in that namespace. This means that you'll need to refer to those constructs as being in that namespace; the long and short of this is that you should define a prefix that maps to that namespace.

Note: If that last sentence didn't make any sense to you, you may need to brush up on your XML, and particularly on how XML Schema works with XML. Consult the Resources at the end of this article (as well as the other articles on the developerWorks XML zone) for more information. For now, you can continue reading, and just trust me -- but you should definitely take the time to fully understand namespaces before considering yourself a JaxMe expert!

In the schema in Listing 1, this was done with the stu prefix. With this prefix, it's easy to define types and then refer to them (using the namespaced prefix) throughout the schema.

You also should be aware that JaxMe works great with the include directive (which is not used in this example). For particularly large schemas, you can segment these definitions into multiple files. Then, in your top-level schema, just reference them as follows:

<!-- Include definitions from another XML Schema -->
<include schemaLocation="file:///dev/jaxme/supplemental/datatypes.xsd"/>

The XML schema processor hands off this information to JaxMe without any distinction of files, so you're advised to use multiple schemas as much as needed.


Resultant classes

Once you have generated the classes, take time to familiarize yourself with what's been created. While these are similar to the constructs created by JAXB, you'll find a few subtle differences.

Student.java

This represents the one XML element (from Listing 1) and is the basic structure for the class hierarchy. It's actually just a very simple interface that extends StudentType (created by JaxMe) and Element, which is part of the JaxMe runtime API. Of course, this class (as well as all other generated classes) is in the com.ibm.dw.jaxme.student package.

StudentType.java

Anything named XXXType in JaxMe (where XXX is a name like "Student" or "Address") is the definition derived from a schema. Listing 2 shows this class's source, which turns out to be pretty self-explanatory.


Listing 2. StudentType generated code
package com.ibm.dw.jaxme.student;

public interface StudentType {
  public String getFirstName();

  public void setFirstName(String pFirstName);

  public String getLastName();

  public void setLastName(String pLastName);

  public AddressType getAddress();

  public void setAddress(AddressType pAddress);

}

This has accessor (getXXX()) and mutator (setXXX()) methods for all its properties, whether they are simple string types or more complex types like Address. Of course, those types are all represented by classes that end in "Type," which is why you see references to AddressType in the generated listings.

AddressType.java and CollegeType.java

Now that you've seen Listing 2 and StudentType.java, these should be pretty obvious. I'll leave you to examine the source for yourself.

ObjectFactory.java

This file is in many ways the bridge between JaxMe and your domain-specific classes. Most important are the methods:

  • newInstance() creates a new element in the domain-specific context and returns it to you.
  • createStudentType() creates a new top-level Student element.

Oddly enough, this file isn't mentioned in any of JaxMe's documentation, and isn't used in any of their examples. Personally, I've found it sort of useful, but I wouldn't recommend relying on it. You can perform all the tasks you need without it, and as it's conspicuously missing in documentation, it could easily disappear in a later release.

Configuration.xml

This XML file handles the mapping from XML to Java code (and back again). It relates elements to classes, fields to properties, and so on. Listing 3 shows the relatively simple mapping file for the sample.


Listing 3. Configuration.xml for example code
<Configuration xmlns="http://ws.apache.org/jaxme/namespaces/jaxme2/configuration">
  <Manager validatorClass="com.ibm.dw.jaxme.student.impl.StudentTypeValidator" 
      qName="{http://dw.ibm.com/jaxme/student}Student" 
         marshallerClass="com.ibm.dw.jaxme.student.impl.StudentTypeSerializer" 
         handlerClass="com.ibm.dw.jaxme.student.impl.StudentHandler" 
         elementInterface="com.ibm.dw.jaxme.student.Student" 
         elementClass="com.ibm.dw.jaxme.student.impl.StudentImpl"/>
  <Manager validatorClass="com.ibm.dw.jaxme.student.impl.AddressTypeValidator" 
      marshallerClass="com.ibm.dw.jaxme.student.impl.AddressTypeSerializer" 
         handlerClass="com.ibm.dw.jaxme.student.impl.AddressTypeHandler" 
         elementInterface="com.ibm.dw.jaxme.student.AddressType" 
         elementClass="com.ibm.dw.jaxme.student.impl.AddressTypeImpl"/>
  <Manager validatorClass="com.ibm.dw.jaxme.student.impl.CollegeTypeValidator" 
      marshallerClass="com.ibm.dw.jaxme.student.impl.CollegeTypeSerializer" 
         handlerClass="com.ibm.dw.jaxme.student.impl.CollegeTypeHandler" 
         elementInterface="com.ibm.dw.jaxme.student.CollegeType" 
         elementClass="com.ibm.dw.jaxme.student.impl.CollegeTypeImpl"/>
</Configuration>

Currently, JaxMe requires you to directly modify this file to change the mapping. The most common change you might want to make is to substitute your own classes for the generated classes. Of course, you'll have to (at least in current versions of JaxMe) generate the default classes and then modify this file. It's also worth noting that this isn't really supported behavior -- the mapping supports it, but it's not particularly well tested or well documented.

Note: In future articles, I may explore this behavior in more detail. If this is of interest to you, please e-mail me or post feedback to this article, and let me know! That's the best way to request coverage of a specific topic.

jaxb.properties

This is the standard JAXB properties file, of course modified for JaxMe. It is just a single line, and tells the JAXB factory classes to use the JaxMe implementation classes, as follows:

javax.xml.bind.context.factory=org.apache.ws.jaxme.impl.JAXBContextImpl

For those of you who are familiar with JAXP, this is exactly the way that implementations like Xerces instruct the JAXP architecture to load their implementations.

impl/*.java

The various source files in the impl sub-directory are all concrete implementations of the interfaces created by JaxMe. Generally, you don't have to worry about these -- they handle the XML processing of your documents, and conversion to Java equivalents.

For those of you who like to look under the hood, these classes are SAX classes, as JaxMe uses SAX to parse XML. In fact, the Type classes implement (indirectly) SAX's org.xml.sax.ContentHandler interface. You'll see methods like startDocument() and characters() in the source code (which is too long to show here).

Although you probably won't have to mess around with these classes much, it's good to have some basic familiarity with them. You'll use them in your code (which I'll show you shortly), and you'll also find an understanding of them quite helpful in troubleshooting and debugging.

Compilation

As a final step in looking at these classes, compile them. This may seem obvious, but you wouldn't believe the questions I get that relate to lack of compilation, or class path issues (also covered, a little later). So before you try to work with your classes, be sure to compile them. As always, I find this is easiest to do with Ant, and I just use ant compile to do the trick.

For those of you doing things the hard way (or who just have a passion for typing javac, be sure to include jaxme-api.jar and jaxme.jar in your class path. jaxme-api.jar contains the JAXB API, while jaxme.jar has the JaxMe implementation classes. As output, you should get everything in both the base and impl directories compiled. Finally, you'll want to copy over the support files used: Configuration.xml and jaxb.properties. Those will be important at run time for marshalling and unmarshalling.


Automation with Ant

You'll find no substitute for a good build tool. It saves you the hassle of dealing with classpath issues over and over again, as well as remembering specific command-line options. This article deals with several tasks, each of which can be handled automatically by Ant. I want to take a little time to let you see my Ant files, so you can incorporate Ant into your own build environment. This also allows me to largely skip this detail in later articles (and cover more meat -- always good, right?).

Class generation

First, you'll want to use JaxMe's schema compiler/class generation tool, represented by the org.apache.ws.jaxme.generator.Generator interface. So you could conceivably use Ant's java target to fire up a specific instance of this interface. However, that's a bit messy -- you are hard-coding in an implementation, and you have to mess with your build file to change that implementation. You could define the implementation class as a property, but that's still messing with fairly low-level coding issues. Fortunately for those of you using Ant, JaxMe includes an Ant taskdef (task definition) for inserting class generation into your build file, and it takes care of all of these details for you. Just tell Ant you've got a custom task definition, as shown in Listing 4.


Listing 4. Ant taskdef for JaxMe
<path id="classpath.schema-generator">
  <pathelement location="${lib}/jaxme2.jar" />
  <pathelement location="${lib}/jaxmejs.jar" />
  <pathelement location="${lib}/jaxmexs.jar" />
  <pathelement location="${lib}/jaxmeapi.jar" />
</path>

<taskdef name="xjc"
         classname="org.apache.ws.jaxme.generator.XJCTask"
         classpathref="classpath.schema-generator"
/>

By including this fragment in an Ant build file, it's trivial to generate classes. You can use the XML shown in Listing 5 to do just that.


Listing 5. Generating classes
  <target name="generate" depends="init">
    <xjc schema="student.xsd"
         target="${dir.generated}">
      <produces includes="com/ibm/dw/jaxme/student/*.java" />
    </xjc>
  </target>

Compiling

With the classes generated, you now need to compile them and copy over your support files. Listing 6 takes care of this task, and even deals with classpath issues.


Listing 6. Compiling classes
  <path id="classpath.schema-compiler">
    <pathelement location="${lib.jaxme}/jaxmeapi.jar" />
    <pathelement location="${lib.jaxme}/jaxme2.jar" />
  </path>			
			
  <target name="compile" depends="generate">
    <javac srcdir="${dir.generated}"
	        destdir="${dir.build}">
	  <classpath refid="classpath.schema-compiler" />
	</javac>
	
	<!-- Copy over support files -->
	<copy todir="${dir.build}">
	  <fileset dir="${dir.generated}">
	    <include name="**/jaxb.properties" />
	    <include name="**/Configuration.xml" />		
	  </fileset>
	</copy>
  </target>

Cleaning up

As obvious as this should be, it's often helpful to be able to clean up what you've done and start from scratch. While this isn't anything JaxMe-specific, it is worth looking at. The typical way to handle this is through a target called clean, as shown in Listing 7.


Listing 7. Cleaning up
  <target name="clean">
    <delete dir="${dir.generated}" />
    <delete dir="${dir.build}" />
  </target>

Listing 8 is a larger Ant file that puts all these elements together. It's actually the file I've used throughout, so it works great for everything described here.


Listing 8. Ant taskdef for JaxMe
<?xml version="1.0" encoding="UTF-8"?>

<project basedir=".">
  <property name="lib.jaxme" value="/Users/bmclaugh/dev/lib" />
  <property name="dir.build" value="build" />
  <property name="dir.generated" value="generated" />

  <path id="classpath.schema-generator">
    <pathelement location="${lib.jaxme}/jaxme2.jar" />
    <pathelement location="${lib.jaxme}/jaxmejs.jar" />
    <pathelement location="${lib.jaxme}/jaxmexs.jar" />
    <pathelement location="${lib.jaxme}/jaxmeapi.jar" />
  </path>
  
  <path id="classpath.schema-compiler">
    <pathelement location="${lib.jaxme}/jaxmeapi.jar" />
    <pathelement location="${lib.jaxme}/jaxme2.jar" />
  </path>

  <taskdef name="xjc"
           classname="org.apache.ws.jaxme.generator.XJCTask"
           classpathref="classpath.schema-generator"
  />
  
  <target name="init">
    <mkdir dir="${dir.generated}" />
	<mkdir dir="${dir.build}" />
  </target>

  <target name="generate" depends="init">
    <xjc schema="student.xsd"
         target="${dir.generated}">
      <produces includes="com/ibm/dw/jaxme/student/*.java" />
    </xjc>
  </target>
  
  <target name="compile" depends="generate">
    <javac srcdir="${dir.generated}"
	        destdir="${dir.build}">
	  <classpath refid="classpath.schema-compiler" />
	</javac>
	
	<!-- Copy over support files -->
	<copy todir="${dir.build}">
	  <fileset dir="${dir.generated}">
	    <include name="**/jaxb.properties" />
	    <include name="**/Configuration.xml" />		
	  </fileset>
	</copy>
  </target>
  
  <target name="clean">
    <delete dir="${dir.generated}" />
    <delete dir="${dir.build}" />
  </target>
</project>

You need to change the value of the lib.jaxme property, and then you're ready to go. In this case, you could simply type ant generate to generate the classes from your schema. You'll want to keep utilities like this around (as well as Ant), as it makes compiling and handling tricky class paths a piece of cake.


What's next?

With a solid understanding of how JaxMe handles class generation, you can easily get started converting to and from XML. I'll tackle that in the next article, and then move on to some JaxMe-specific features like working with databases. Until then, try messing around with mapping and Configuration.xml -- you'll have a good time (probably breaking things once or twice) and really get a handle on how JaxMe works. While you're doing that, I'll be working on the next installment -- see you then!



Download

NameSizeDownload method
x-pracdb4-code.zip2KB HTTP

Information about download methods


Resources

About the author

Brett McLaughlin has been working in computers since the Logo days. (Remember the little triangle?) He currently specializes in building application infrastructure using Java-related technologies. He has spent the last several years implementing these infrastructures at Nextel Communications and Allegiance Telecom, Inc. Brett is one of the co-founders of the Java Apache project Turbine, which builds a reusable component architecture for Web application development using Java servlets. He is also a contributor to the EJBoss project, an open source EJB application server, and Cocoon, an open source XML Web-publishing engine.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML
ArticleID=12414
ArticleTitle=Practical data binding: JaxMe - The new kid on the block
publish-date=07092004
author1-email=brett@oreilly.com
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Try IBM PureSystems. No charge.

Special offers