CXF @WebService and XMLGregorianCalendar with JAXB

Lately we’ve done a lot of work with some different web-services and at one point we discovered that some people have trouble formatting their timestamps properly. Good solution would be to ask people to use a proper standard and not re-invent their own wheels, but that’s not always a possibility. Fortunately there’s a rather simple solution for this. All you need is to define a @XmlJavaTypeAdapter and teach it how to convert different values into suitable formats.

JAXB and XML by default uses a timestamp format of “yyyy-MM-dd’T’HH:mm:ss’Z'” which translates to 2015-04-11T14:15:12.000 roughly and some people think it’s ok to send us SQL ISO format timestamps that look very similar – specifically missing the T letter in the timestamp, like this: “yyyy-MM-dd HH:mm:ss”.

For example, in my web service entity I have a RelaxedXMLGregorianCalendarAdapter in use which is our own implementation:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType
@XmlRootElement(name = "Metainfo")
public class Metainfo {
    @XmlJavaTypeAdapter(RelaxedXMLGregorianCalendarAdapter.class)
    protected XMLGregorianCalendar generationTime;
}

And here’s the implementation for the adapter (note that we turn null, empty string and specifically a word “infinity” into null’s):

import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

public class RelaxedXMLGregorianCalendarAdapter extends XmlAdapter<String, XMLGregorianCalendar> {

	@Override
	public String marshal(XMLGregorianCalendar v) {
		return v.toXMLFormat();
	}

	@Override
	public XMLGregorianCalendar unmarshal(String v) throws Exception {

		if (v == null) {
			return null;
		}
		
		if (v.trim().isEmpty()) {
			return null;
		}
		
		// Who thinks that this is OK for a date field?
		if ("infinity".equals(v.trim())) {
			return null;
		}
                // Replace the space with T to match our default pattern.
		return DatatypeFactory.newInstance().newXMLGregorianCalendar(v.replace(" ", "T"));
	}
}

So there you have it. This is how you can customize how JAXB is handling some type conversions and pretty much you can customize anything JAXB does with this approach. Like teach it to treat -1 for specific fields as null or teach it understand different date formats.

About Reigo Reinmets

Enterprise Software consultant with 9 years of experience in enterprise software world who’s working on various projects that are mostly based on Liferay. Most blog posts here are real-life findings and issues we’ve encountered while working on projects and Java tutorials on Liferay.

Leave a Reply

Your email address will not be published. Required fields are marked *