I have a problem with the way JAXB is generating the bound classes for an XML schema (which, for sake of precision, I cannot modify). I want to map a xsd:date type to a Joda
You do not need to extend XmlAdapter
and with Joda-Time v2, you do not even need to implement static methods, as they are already provided.
<jaxb:javaType xmlns="http://java.sun.com/xml/ns/jaxb"
name="org.joda.time.LocalDate"
xmlType="xs:date"
parseMethod="org.joda.time.LocalDate.parse"
printMethod="java.lang.String.valueOf"
/>
See JAXB datatype converters for xs:date xs:time and xs:dateTime
You are extending XmlAdapter
which is used when you want to annotation your Java model for JaxB, that is through the annotation @XmlJavaTypeAdapter(Adapter1.class)
. For your case you just need a class with static methods that does not extend XmlAdapter
. You will need the parse method (take a string and return date) and print method (take a date and return a string) and that's about it.
I was in a WSDL first context: no java at all, just generate a CXF Client from a provided WSDL.
I was stuck with the ugly Adapter1.java
for a long time, but I found the solution there.
You will use a custom XMLAdapter like already explained.
The key of this problem was adding the xjc
extension to the global binding file:
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jaxb:extensionBindingPrefixes="xjc" jaxb:version="2.1">
<jaxb:globalBindings>
<xjc:javaType adapter="com.xxx.tools.xjc.DateAdapter"
name="java.util.Date" xmlType="xs:dateTime" />
</jaxb:globalBindings>
</jaxb:bindings>
xjc extension allow the usage of xjc:javaType
that accept adapter parameter. No more static method required !
Note this seems to work with jaxb 2.1+ only.
When generating XmlAdapters from an XML schema you need to put the logic for the conversion in static methods not in an XmlAdapter
. This is so an XmlAdapter
that leverages that logic can be generated. I recognize that this is an odd mechanism.
Complete Example
A complete example. This is your bindings.xml:
<jaxws:bindings wsdlLocation="YourWsdl"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
jxb:extensionBindingPrefixes="xjc">
<jaxws:bindings node="wsdl:definitions/wsdl:types/xs:schema[@targetNamespace='YourTargetNameSpace']">
<jxb:globalBindings xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xjc:javaType adapter="com.xxx.your.package.DateAdapter" name="java.util.Date" xmlType="xs:dateTime" />
</jxb:globalBindings>
</jaxws:bindings>
</jaxws:bindings>
plus the Java Class:
package com.yourpackage;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import javax.xml.bind.DatatypeConverter;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class DateAdapter extends XmlAdapter<String, Date>
{
@Override
public Date unmarshal(final String date) {
return DatatypeConverter.parseDate(date).getTime();
}
@Override
public String marshal(final Date date)
{
Calendar calendar = new GregorianCalendar();
calendar.setTime(date);
return DatatypeConverter.printDate(calendar);
}
}
plus the pom.xml definition:
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>${cxf.version}</version>
<dependencies>
<dependency>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics</artifactId>
<version>0.6.4</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>${project.build.directory}/generated/cxf</sourceRoot>
<defaultOptions>
<autoNameResolution>true</autoNameResolution>
</defaultOptions>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/src/main/resources/your.wsdl</wsdl>
<extraargs>
<extraarg>-verbose</extraarg>
<extraargs>-xjc-npa</extraargs>
<extraarg>-xjc-Xsetters</extraarg>
</extraargs>
<bindingFiles>
<bindingFile>${basedir}/src/main/resources/binding.xml</bindingFile>
</bindingFiles>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
You do not need to extend XmlAdapter
.
Just create static methods on a POJO and it will work.
Example:
public class DateAdapter {
private static DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyyMMdd");
public static LocalDate unmarshal(String v) throws Exception {
return fmt.parseLocalDate(v);
}
public static String marshal(LocalDate v) throws Exception {
return v.toString("yyyyMMdd");
}
}