Monday, 22 June 2009

JAXB Custom Data Binding

In a previous post I experimented consuming WCF web services using various Java WS frameworks and tools. As pointed out by Alex, the one that I missed out was wsimport which is bundled as part of JSE6.

Like many other tools, it supports both Ant task and command line interface (CLI). The CLI for wsimport is quite simple - in my case I generated the source code and client stub library like so:

D:\Program Files\Java\jdk1.6.0_11\bin>wsimport -d /temp/generated -s /temp/gensrc -keep http://localhost/PromoService.svc?wsdl
parsing WSDL...


generating code...

D:\Program Files\Java\jdk1.6.0_11\bin>
All the rest is similar to the results of IntelliJ shown in my previous post. There are two problems with the generated PromoInfo.java which is a data/value object:
  1. string fields are generated as JAXBElement<String>
  2. dateTime fields are generated as XMLGregorianCalendar
I want to use core java data types on the data objects so that they can be easily integrated with other frameworks without having to do conversion. Examining my schema (on http://localhost/PromoService.svc?xsd=xsd2) the PromoInfo complex type is defined as


  
    
      
      
      
      
    
  


It is obvious that the xs:string and xs:dateTime were not converted into the desired java types. To solve my problems I specified customised JAXB binding rules in an external file - custombinding.xml like so

 
     
 

The attribute generateElementProperty="false" on line 2 tells wsimport not to generate JAXBElement but to generate native java data types instead.

The javaType element on line 3 defines the binding between "xs:dateTime" and "java.util.Date" because by default xml dateTime binds to javax.xml.datatype.XMLGregorianCalendar as shown here.

Once the binding is defined, rerunning the wsimport tool with the -b switch will produce the desired output:
D:\Program Files\Java\jdk1.6.0_11\bin>wsimport -d /temp/generated -s /temp/gensrc -b /temp/custombinding.xml http://localhost/PromoService.svc?wsdl
parsing WSDL...


generating code...
Note: D:\temp\gensrc\org\w3\_2001\xmlschema\Adapter1.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.

This time the generated PromoInfo.java looks much better:
...
public class PromoInfo {

    @XmlElement(name = "PromoDateTime", type = String.class)
    @XmlJavaTypeAdapter(Adapter1 .class)
    @XmlSchemaType(name = "dateTime")
    protected Date promoDateTime;
    @XmlElement(name = "PromoDescription", nillable = true)
    protected String promoDescription;
    @XmlElement(name = "PromoName", nillable = true)
    protected String promoName;
    @XmlElement(name = "PromoVenue", nillable = true)
    protected String promoVenue;
...


4 comments:

brian said...

Thanks for the instructions, these helped. However I got this error when running the wsimport CLI:

[ERROR] undefined element declaration 'xs:schema'

I found the solution for the error here:

http://weblogs.java.net/blog/vivekp/archive/2007/05/how_to_deal_wit_1.html

Romen Law said...

Thanks for the pointer Brian.

Dan Fetzer said...
This comment has been removed by the author.
Dan Fetzer said...

Your example was helpful, but note that the "globalbindings" tag should have an uppercase "B". I.e., "globalBindings".