Friday, May 20, 2011

Java Class Generator

One of the biggest issues I had when switching from SOAP web services to REST was the lack of a WSDL. Now I know that a WADL can be used in it's place, but I have had issues with it when working with custom complex objects. To get around this issue, I have been advocating the use of XSD files. The XSD file describes every field within an object. If you create one of these for your services request and response objects, you will then be able to share the XSD file with others so that they can easily create clients to your services.

This all seems like a great idea, but before when we were using the WSDLs everything was generated for us, now we are expected to create classes and XSD files by hand? With bigger objects this could be very time consuming. To overcome this issue, I have created an ANT script that generates Java classes from XSD files. If you place all of the XSD files and the script in a single folder, the script will generate all the required Java classes with annotations required by JAXB. (If you are not using JAXB, I would love to know what you are using, and don't say XStream)

Below is a link to the actual script, but before we jump to that, let's look it over.

We are using XJC to generate the classes. This is something that comes bundled with Java, so the only extra jar file that we need is antcontrib.jar. This file can be found here. We then need to make sure this jar is visible from to our script.

<path id="classpath">
  <fileset dir="${lib.dir}" includes="*.jar" />
 </path>
 
 <taskdef resource="net/sf/antcontrib/antcontrib.properties">
    <classpath refid="classpath" /> 
 </taskdef>

Next comes the meat of the script. We are going to iterate over every XSD file in the directory and generate a class for it.
 <target name="all">
  <foreach target="generate" param="fileName">
   <fileset dir="${xsd.dir}" casesensitive="yes">
    <include name="*.xsd"/>
    <exclude name="*.xml"/>
   </fileset>
  </foreach>
 </target>

Once we have the file we want, we use an existing xjc task to create the class.

<xjc destdir="${output.dir}" package="${output.namespace}">
   <schema dir="${xsd.dir}" includes="${basename}" />
   <depends dir="${xsd.dir}" includes="*.xsd" />
   <produces dir="${xsd.dir}" includes="*.xsd" />
   <arg value="-verbose"/>
  </xjc>

That's all there is to it, run the script using Java 1.6 and the classes will appear before your eyes. Now with the time you saved creating those classes, you can go through and do a better job unit testing your actual work.

Food for thought: Which should first the XSD file or the class?

View entire script: DTOGenerator.xml