Solving unmarshalling problems with Jaxb/CXF

Introduction

This tutorial gives a quick introduction to Jaxb and shows how to fix some common unmarshalling problems with generated CXF web service clients, or other generated clients that make use of the Jaxb api.
It assumes the reader is a Java developer familiar with the basics of classic webservices. He should know a wsdl describes a webservice. He should also know that a webservice client communicates with the webservice by sending a soap request in xml, after which the server (hopefully) responds with a soap response, which is in xml too.

Context

Many Java developers have to make a webservice client from a wsdl from time to time.
Usually, they use a wsdl2java tool to do that, which comes with every major web services framework I know, such as Axis or Cxf, the former Xfire.

One of the things this client will do is, when sending a request, transform – “marshall” – Java objects to a soap xml snippet so they can be included as parameters in the soap request. And when receiving the soap response from the server, the client will have to map the xml snippets in the response back to Java objects – the “unmarshalling” -, so we can easily work with the received response from Java.

To do this marshalling and unmarshalling, the generated code usually makes use of some specific apis.
Cxf, for example, uses Jaxb to marshall java objects to and unmarshall java objects from XML.

What is Jaxb?

Jaxb, the Java Architecture for XML Binding, is part of the jee stack.
Its job is exactly what I just described: to marshal Java objects into XML and to unmarshal XML back into Java objects.

The Jaxb annotations tell a(n) Jaxb (Un)marshaller how to (un)marshall an Item object/xml snippet.
The @XmlRootElement annotation tells jaxb that the xml equivalent of this class can be the root of an xml document.
The @XmlAttribute annotation tells jaxb to map this property as an xml attribute. If no annotation here wouldnt be specified, the property would still be mapped in the xml, but as a subelement instead of an attribute.
If you dont want the property to appear in the generated xml at all, you have to use @XmlTransient.

In the above class, we are trying to unmarshall the xml we got from the previous section back into the java object. Note however, that we made a modification, which will cause the unmarshalling to fail.
We made the price attribute empty instead of passing “10″.
Running this class will result in a “NumberFormatException at java.math.BigDecimal.<init>” exception.
If we would make the catalog-number empty instead, this would result in a “NumberFormatException: Zero length BigInteger at java.math.BigInteger.<init>” exception.

And some webservices will actually return xml like that. Ive already had to work twice with a web service implemented in .NET(the default marshaller in .NET seems to wrap bigintegers and bigdecimals as an empty string?) that returned something like biginteger=”" in the soap response.

Jaxb XmlAdapters

When calling an external webservice, we have no control over what is returned in the soap response. Hence, we will need to fix the problem at the moment we are unmarshalling. Luckily, Jaxb makes it possible to register custom unmarshallers in the form of XmlAdapters.

The above adapter will marshall and unmarshall BigDecimals the standard way, with the exception that if the String has an illegal value at unmarshalling, it will just unmarshall it as null, instead of crashing the whole unmarshalling process. I wrote a similar one for the BigInteger problem: BigIntegerXmlAdapter.

Registering XmlAdapters for a whole package

Although you can register XmlAdapters at a detailed level, per class for example, it is not the easiest method to use them for generated clients. It is likely that you ended up with tons of classes, and you dont want to go annotate all of them seperately.

Luckily, we can just put them in the package declaration file package-info.java of our pojo package:

Thank you for sharing this. I have an additional question. I have generated a client using a wsdl and wsdl2java. All worked well until the strucure / wsdl was extended by the supplier (n external party). I noticed this when receiving unmarshall exceptions. The external party stated they will update the structure / wsdl reguarly, without notice. The new wsdl will be backwards compatible (ie. only extensions are made).
Is there a way to overcome unmarshall exceptions for new attributes in the return message from the server / ie. skip unknown attributes in the return message?