Tuesday, August 28, 2007

Developer-friendly JAXB code generation with JAXB Commons and binding file

In my previous post "Defining service/component interfaces in WSDLs", I mentioned that "Not only are no-argument constructors and all public getter and setter methods generated for complex types, but also other useful methods, such as valued constructors, builder methods, hashCode, equals and toString methods can be implemented using XJC extensions." This post is about how to do this.

Our project uses XFire's WsGenTask Ant task to generate service interfaces, DTO classes and exceptions from WSDL file and the referenced XSD files. WsGenTask delegates the generation of DTO classes to JAXB's XJC compiler. However, these DTO classes generated by JAXB XJC's default are not particularly developer-friendly, in the following aspects:
  1. They have only one default constructor. This is quite inconvenient when you need to instantiate a DTO to hold some values:

    • You need to declare a local variable, which may otherwise be unnecessary.

    • You need to call the constructor to instantiate a new instance, then you need to invoke the setter methods for each property value you would like to it to hold.

    • To re-use the code and get rid of the local variable declaration, you need to create a factory class with one or more overloading create methods for each DTO class, which essentially are value-taking constructors moved to a factory class.

  2. They do not override the hashCode(), equals(Object) and toString() methods of the Object class. DTOs are value objects and no identity. Two instances holding exactly the same data should be considered interchangeable. Thus, overriding hashCode() and equals(Object) is essential for DTO classes. Moreover, not overriding toString() implementation makes it inconvenient in unit testing:

    • You cannot invoke assertEquals(Object, Object) directly. You have to rely on a static method to determine whether two objects are equal in values. And if the assertion fails, you need to invoke another static method to have a useful string representation of both the expected and actual objects.

  3. Default values are not honoured in the generated classes, that means you have to set the value explicitly even if you are using a default value in most cases.

  4. If you are not the owner of the schemas being used, the class and property names generated may not be following the Java's camel-case conventions.
  5. There is no setter method for collections. You need to invoke the getter method to retrieve the collection and invoke the addAll(Collection) method to add all elements of the prepared collection.

  6. If an element has a maxOccurs attribute value greater than one, the getter method generated is not using plural by default.

  7. Date, time and dateTime are generated as XMLGregorianCalendar, which requires constant conversion to and from the java.util.Date and java.util.Calendar values you use in your domain models.

Fortunately, XJC has an extension option that allows third-party extensions. A whole bunch of XJC plugins have been developed to iron out most of these isses in the open source community, and many of them are under the JAXB 2.0 Commons project hosted by java.net.

Many of the these plugins are very useful:
  1. The Value Constructor plugin generates a constructor that takes values for all properties besides the default no-argument constructor.

  2. If you have many properties in a DTO class, or some of the properties are optional, you can use the Fluent API plugin, which generates builder-styled methods, which essentially provides named-parameter constructor, which is not provided by Java.

  3. The jakarta-commons-lang plugin generates overriding hashCode(), equals(Object) and toString() methods using jakarta commons lang's HashCodeBuilder, EqualsBuilder and ToStringBuilder classes, which in turn uses reflection.

  4. The Default Value plugin honours the default values specified in the schemas.

  5. The CamelCase Always plugin generates class and property names following the camel-case convention.

  6. The Collection Setter Injection plugin generates setter methods for collections.


Unfortunately, at the time of this writing, XFire's WsGen does not pass parameters to JAXB's XJC, as tracked by this XFIRE-1038 JIRA. The way to get around it is to call the XJCTask Ant task after the WsGenTask call and overwrite all DTOs generated by WsGenTask.

Note that some of the plugins required JAXB 2.1 to work. If you intend to use JAXB 2.0 in runtime environment, it is fine: you can generate the classes using JAXB 2.1 with the target specified as "2.0" to avoid generating annotations introduced in JAXB 2.1.

To generate a plural form for collections, use a simple JAXB binding file with XJCTask.

If you would like to work with java.util.Date or java.util.Calendar instead of XMLGregorianCalendar, you can provide your own parseMethod and printMethod and specify them in your JAXB binding file used by XJCTask, as detailed by Sun's engineer Kohsuke's blog entry.

Follwing are extracted from the ant build file to illustrate how to generate developer-friendly DTO classes using JAXB:

<!-- This task will autogenerate the code from the XSD specification -->
<taskdef name="xjc" classname="com.sun.tools.xjc.XJCTask" >
<classpath>
<pathelement path="${jaxb1-impl-2.1.3.jar}:${jaxb-api-2.1.3.jar}:${jaxb-impl-2.1.3.jar}:${jaxb-xjc-2.1.3.jar}" />
<pathelement path="${jaxb2-commons-commons-lang-plugin.jar}"/>
<pathelement path="${jaxb2-commons-value-constructor.jar}"/>
<pathelement path="${jaxb2-commons-fluent-api.jar}"/>
<pathelement path="${jaxb2-commons-default-value-plugin.jar}"/>
<pathelement path="${jaxb2-commons-collection-setter-injector.jar}"/>
<pathelement path="${component.classpath}" />
</classpath>
</taskdef>

<!-- This task will autogenerate the code from the WSDL specification -->
<taskdef name="wsgen" classname="org.codehaus.xfire.gen.WsGenTask" >
<classpath>
<pathelement path="${component.classpath}" />
</classpath>
</taskdef>

<!-- Auto generate classes based on the XSD definitions using JAXB bindings -->
<target name="xjc_gen">
<mkdir dir="${component.autogen_src}"/>
<delete>
<fileset dir="${component.autogen_src}"
excludes="**/service/**/*.java"/>
</delete>
<xjc destdir="${component.autogen_src}" target="2.0" extension="true">
<arg value="-Xcommons-lang"/>
<arg value="-Xvalue-constructor"/>
<arg value="-Xfluent-api"/>
<arg value="-Xcollection-setter-injector"/>
<arg value="-Xdefault-value"/>
<schema dir="${component.home}/src/conf/wsdl" includes="*.xsd"/>
<binding file="${component.home}/src/conf/wsdl/simple.xjb"/>
</xjc>
</target>

<!-- Auto generate interfaces and classes based on the WSDL definitions using JAXB bindings -->
<target name="wsdl_gen">
<mkdir dir="${component.autogen_src}"/>
<wsgen outputDirectory="${component.autogen_src}"
wsdl="${component.home}/src/conf/wsdl/service-foo.wsdl"
package="com.blogspot.ozgwei.service.foo"
overwrite="true"
binding="jaxb"
externalBindings="${component.home}/src/conf/wsdl/simple.xjb"
/>
<wsgen outputDirectory="${component.autogen_src}"
wsdl="${component.home}/src/conf/wsdl/service-bar.wsdl"
package="com.blogspot.ozgwei.service.bar"
overwrite="true"
binding="jaxb"
externalBindings="${component.home}/src/conf/wsdl/simple.xjb"
/>
</target>

<!-- Build all user, autogenerated and test code -->
<target name="compile" depends="wsdl_gen, xjc_gen">
...
</target>


The next is the content of the simple.xjb file for JAXB Binding, which use java.util.Calendar:

<!--
This enables the simple binding mode in JAXB.
See http://weblogs.java.net/blog/kohsuke/archive/2006/03/simple_and_bett.html
-->
<jaxb:bindings jaxb:version="2.0" jaxb:extensionBindingPrefixes="xjc"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<jaxb:globalBindings>
<xjc:simple/>
<jaxb:javaType name="java.util.Calendar" xmlType="xs:date"
parseMethod="javax.xml.bind.DatatypeConverter.parseDate"
printMethod="javax.xml.bind.DatatypeConverter.printDate"/>
<jaxb:javaType name="java.util.Calendar" xmlType="xs:time"
parseMethod="javax.xml.bind.DatatypeConverter.parseTime"
printMethod="javax.xml.bind.DatatypeConverter.printTime"/>
<jaxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"
parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime"
printMethod="javax.xml.bind.DatatypeConverter.printDateTime"/>
</jaxb:globalBindings>
</jaxb:bindings>


If you prefer to use java.util.Date instead of java.util.Calendar, define the following class and change the binding file accordingly:

package com.blogspot.ozgwei.jaxb

import java.util.Date;
import javax.xml.bind.DatatypeConverter;

public class DateConverter {

public static Date parseDate(String s) {
return DatatypeConverter.parseDate(s).getTime();
}

public static Date parseTime(String s) {
return DatatypeConverter.parseTime(s).getTime();
}

public static Date parseDateTime(String s) {
return DatatypeConverter.parseDateTime(s).getTime();
}

public static String printDate(Date dt) {
Calendar cal = new GregorianCalendar();
cal.setTime(dt);
return DatatypeConverter.printDate(cal);
}

public static String printTime(Date dt) {
Calendar cal = new GregorianCalendar();
cal.setTime(dt);
return DatatypeConverter.printTime(cal);
}

public static String printDateTime(Date dt) {
Calendar cal = new GregorianCalendar();
cal.setTime(dt);
return DatatypeConverter.printDateTime(cal);
}

}


The simple.xjb will be changed to:

<jaxb:bindings jaxb:version="2.0" jaxb:extensionBindingPrefixes="xjc"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<jaxb:globalBindings>
<xjc:simple/>
<jaxb:javaType name="java.util.Date" xmlType="xs:date"
parseMethod="com.blogspot.ozgwei.jaxb.DateConverter.parseDate"
printMethod="com.blogspot.ozgwei.jaxb.DateConverter.printDate"/>
<jaxb:javaType name="java.util.Date" xmlType="xs:time"
parseMethod="com.blogspot.ozgwei.jaxb.DateConverter.parseTime"
printMethod="com.blogspot.ozgwei.jaxb.DateConverter.printTime"/>
<jaxb:javaType name="java.util.Date" xmlType="xs:dateTime"
parseMethod="com.blogspot.ozgwei.jaxb.DateConverter.parseDateTime"
printMethod="com.blogspot.ozgwei.jaxb.DateConverter.printDateTime"/>
</jaxb:globalBindings>
</jaxb:bindings>

Tuesday, August 21, 2007

Defining service/component interfaces in WSDLs

We have just completed an iteration of the project we have been working on for the past few months. Now it's a good time to summarise the experiences we have gained so far.

Probably the most significant one is defining all service/component interfaces in WSDLs.

The project started with the interfaces of a few services being defined in WSDLs because they are invoked by the web tier as web services call. Since the JAXB-generated Java classes of some complex types defined in the XML schema are reused in some other service interfaces that are not originally intended to be invoked via web services, we finally decided to define all service interfaces in WSDLs, regardless whether they are intended to be invoked as web services or not. And this brought us unexpected benefits and productivity.

So what are the benefits of defining all service interfaces in WSDLs?

First of all, it takes away most of the tedious work of implementing Data Transfer Objects (DTOs), resulting in higher productivity. If you wonder why DTOs are still in use when domain model objects persisted by Hibernate and JPA can be passed back to service clients directly, please read my previoug blog entry: DTOs are a necessary devil in building SOA enterprise applications.

So, how does defining service interfaces in WSDLs take away the boring implementation of DTOs? In a WSDL file, each operation has input messages, output messages and/or fault messages, which in turn are defined as elements in an external or embedded XML schema. And each element is declared in an XML type. The XJC compiler from JAXB can be used to generate corresponding Java classes of any complex types and some restricted simple types. These classes are data holders with absolutely no behaviours; in other words, they are DTOs. Code generation of DTOs has other benefits: no behaviours can be added to the DTOs without subclassing and defining new operations; and these DTOs won't accidentally reference any domain model objects, which is always a concern for hand-coded DTOs.

XML schema allows very rich type definitions, such as abstract types and type inheritance, which has corresponding concepts in object-oriented languages, such as Java, making it a perfect choice to generate Java classes from XML data types.

Not only are no-argument constructors and all public getter and setter methods generated for complex types, but also other useful methods, such as valued constructors, builder methods, hashCode, equals and toString methods can be implemented using XJC extensions. These are to be blogged in a follow-up post.

Moreover, defining service/component interfaces in WSDLs can partially enforce the "contract" using schema validation, promoting the best practice of "Design by Contract" (DBC).

Java, by itself, does not provide native support to DBC. Any acceptable input values, return values and exceptions are only documented using javadoc in the interfaces. The implementation classes have to do all the hard work to validate input values, such as making sure a mandatory parameter is not null, an amount is greater than zero and less than a preset limit, etc.

Meanwhile, XML schema provides a rich basic data types, such as positive integers. It can also specify whether an element is mandatory or not using the "minOccur" attribute. Furthermore, it allows you to add restrictions to simple types, such as the maximum length of a string and regular expression patterns that must be matched by a string. Thus, XML schema validation can catch many simple field validation errors. More complex validations, such as cross-field validations and business rule validations cannot be done by schema validation. However, they can still be documented using annotations, which are generated as Java comments in the generated Java classes.

Another benefit of defining service/component interfaces in WSDLs is that it promotes the best practice of "contract-first" web service design. Because the service interface is defined in a WSDL file, the service is web service ready, even if it is not intended to be used as a web service at this stage. The opposite of "contract-first" is "code-first". When adopting a "code-first" practice, the service interfaces are defined in Java, potentially without using DTOs. When the service needs to be accessed via web services or remotely, it is not as easy as just exposing the service as a web service by, say, wiring up the Spring application context. A proper service interface using DTOs has to be defined and implemented by delegate calls to the original interface and doing all the transformation between DTOs and domain models. Even if DTOs are used in the original Java interface, exposing the service as a web service is not as simple as adding the JSR-181 annotations to the interface and all DTOs: some common Java types do not have a counterpart in XML, such as java.util.Map. Moreover, the methods defined in your original DTOs may not be suitable for JAXB use. You may not have defined a no-argument constructor; you may not have defined a setter method for each property... So, why go the hard way when defining the interfaces in WSDLs can save you the tedious work of implementing DTOs and, at the same time, provide an elegant way to expose it as a web service when the time calls?

Saturday, August 18, 2007

DTOs are a necessary devil in building SOA enterprise applications

Bringing up the topic of Data Transfer Objects (DTOs), many people's first thought would probably be that it was a reminiscence of the old Enterprise Java Bean (EJB) 2.0.

Hibernate, JDO and JPA have made it possible to eliminate DTOs from web applications. However, DTOs are a necessary devil when building an enterprise application, especially in a Service-Oriented Architecture (SOA).

For each service or component, the underneath domain model that provides the service should be encapsulated and not leaked beyond the boundary of the service's interfaces.

It is often said that the interfaces are the contracts between the client and the provider of the services. However, many new Java developers think that only the interface classes and their method names are the contract without realising that any objects passed in and out of these operations are also part of the contract, such as method parameters, return values and thrown exceptions. And the contractual binding is transitive by reachability, that is, all classes directly or indirectly referenced by these parameters, return values and exceptions are all part of the contract. Therefore, if domain models are passed in and out of any operation defined in the service interfaces, they are leaked, making service clients susceptible to any changes in the domain models, which are the implementation details that are supposed to be encapsulated.

For a web application, this is probably not a big deal, as the presentation tier is typically closely coupled to the service and persistence tiers. However, for any enterprise applications in a Service-Oriented Architecture, the change of interfaces can have a ripple effect.

In order to achieve the encapsulation, DTOs are used as the parameters, returned values and exceptions in operations defined in the interfaces to isolate domain models from the outside world. For this reason, it is not hard to imagine that DTOs are ubiquitous in a SOA world.

Thursday, August 9, 2007

EasyMock Class Extension 2.2 Gotcha

EasyMock mocks interfaces, and the Class Extension mocks classes.

When using the class extension, the EasyMock from the org.easymock.classextension package should be used instead of the same-named class from the original org.easymock package.

When working with more than one mocks with Java 5, we can invoke the replay and verify methods using varargs, such as:
import static org.easymock.classextension.EasyMock.*;
...
replay(mockCustomerRepository, mockCustomer);
...
verify(mockCustomerRepository, mockCustomer);
However, if one of the mocks is mocking a class instead of an interface, I got an IllegalArgumentException: not a proxy instance.

Looking into the stack trace, I can see the EasyMock.replay/verify from the original org.easymock package is used instead of the one from org.easymock.classextension package, as stated in the import statement.

What happened is: org.easymock.classextension.EasyMock extends the org.easymock.EasyMock without providing a vararg version of replay(Object...) and verify(Object...) method. Thus, when the vararg versions are invoked, the control is passed to the vararg version of its super class, which only mocks interfaces using standard Java Proxy.

To get around this, you invoke the single parameter version, such as:
import static org.easymock.classextension.EasyMock.*;
...
replay(mockCustomerRepository);
replay(mockCustomer);
...
verify(mockCustomerRepository);
verify(mockCustomer);
Of course, this gotcha only exists in EasyMock class extension 2.2. The latest 2.2.2 version provides vararg version for these two methods. So a better solution is to upgrade to this latest version.