简体   繁体   中英

Replacing date of type XmlGregorianCalendar generated by wsdl to java.util.Date?

I am working on an application in which we give call to Third Party SAP system using files generated through wsdl using Spring webservices.

One of the file generated using wsdl through ws import have Date attribute of type "XMLGregorianCalendar" and in response we are getting null value for corresponding field .

I want to convert date from XmlGregorianCalendar to java.util.Date.

Have referred : how replace XmlGregorianCalendar by Date? but not able to provide appropriate xjb bindings through wsdl.

If anyone can suggest the conversion of Dates generated by wsdl ,it would be of great help..... Thanks In Advance ! Shuchi

WSDL has no deal with xjb. xjb is for xjc compiler passed as -b parameter. ie

xjc -b <file>

documentation: Customizing JAXB Binding

if you use Maven plugins to generate your JAXB Java classes any of them have Binding configuration ie

<groupId>org.apache.cxf</groupId>
                <artifactId>cxf-codegen-plugin</artifactId>
                <configuration>
                    <defaultOptions>
                        <bindingFiles>
                            <bindingFile>${project.interfaces.basedir}Configuration/Bindings/common-binding.xjb</bindingFile>
                        </bindingFiles>

or

<plugin>
            <groupId>org.jvnet.jaxb2.maven2</groupId>
            <artifactId>maven-jaxb2-plugin</artifactId>
            <configuration>
                <schemaDirectory>${basedir}/src/main/resources/XMLSchema</schemaDirectory>
                <bindingDirectory>${basedir}/src/main/resources/Bindings</bindingDirectory>
            </configuration>

and so on...

xjb for it is very simple:

<jaxb:bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jaxb:extensionBindingPrefixes="xjc">
<jaxb:globalBindings>
    <jaxb:serializable uid="1" />
    <jaxb:javaType name="java.util.Calendar" xmlType="xsd:dateTime"
        parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime"
        printMethod="javax.xml.bind.DatatypeConverter.printDateTime" />
    <jaxb:javaType name="java.util.Calendar" xmlType="xsd:date"
        parseMethod="javax.xml.bind.DatatypeConverter.parseDate" printMethod="javax.xml.bind.DatatypeConverter.printDate" />
    <jaxb:javaType name="java.util.Calendar" xmlType="xsd:time"
        parseMethod="javax.xml.bind.DatatypeConverter.parseTime" printMethod="javax.xml.bind.DatatypeConverter.printTime" />            
</jaxb:globalBindings>

as you can see it defines conversions from xsd:dateTime, xsd:date and xsd:time types to java.util.Calendar.

I do not recommend to use java.util.Date. There are many troubles with Date handling (especially with different timeZones). It is better to use java.util.Calendar. Calendar is much easier to handle and default converter implementation is there in JDK:

javax.xml.bind.DatatypeConverter

But, if you still want to use java.Util.Date you need to have your own small converter with two static methods "parse" and "print" and then set it in xjb. ie

public class MyDateConverter {
    public static java.util.Date parse(String xmlDateTime) {
        return javax.xml.bind.DatatypeConverter.parseDateTime(xmlDateTime).getTime();
    }

    public static String print(Date javaDate) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(javaDate.getTime());
        return javax.xml.bind.DatatypeConverter.printDateTime(calendar);
    }
}

your conversions in xjb will look like:

<jaxb:javaType name="java.util.Date" xmlType="xsd:dateTime"
    parseMethod="MyDatatypeConverter.parse"
    printMethod="MyDatatypeConverter.print" />

You have to create a custom Data type adaptor and add in binding file.

 <jaxb:globalBindings>
    <xjc:serializable uid="-6026937020915831338" />
    <xjc:javaType name="java.util.Date" xmlType="xs:date" 
          adapter="com.test.util.jaxb.DateDataTypeAdapter" />
  </jaxb:globalBindings>
</jaxb:bindings>

Class DateDataTypeAdapter

package com.test.util.jaxb;

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

public final class DataTypeAdapter {
    private DataTypeAdapter() { }

    public static Date parseDate(String s) {
        if (s == null) {
            return null;
        }

        return DatatypeConverter.parseDate(s).getTime();
    }

    public static String printDate(Date dt) {
        if (dt == null) {
            return null;
        }

        Calendar c = Calendar.getInstance();
        c.setTime(dt);

        return DatatypeConverter.printDate(c);
    }

    public static Date parseDateTime(String s) {
        if (s == null) {
            return null;
        }

        return DatatypeConverter.parseDateTime(s).getTime();
    }

    public static String printDateTime(Date dt) {
        if (dt == null) {
            return null;
        }

        Calendar c = Calendar.getInstance();
        c.setTime(dt);

        return DatatypeConverter.printDateTime(c);
    }
}

I have change the bean's java type from XMLGregorianCalendar adding the configuration for jaxb directly on the xsd's contracts.

I have done like this, note the xs:annotation :

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://hello.eomm.it/springws"
targetNamespace="http://hello.eomm.it/springws" elementFormDefault="qualified" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="2.0">

<xs:annotation> 
    <xs:appinfo>
        <jaxb:globalBindings>
            <jaxb:serializable uid="1" />
            <jaxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"
                parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime" printMethod="javax.xml.bind.DatatypeConverter.printDateTime" />
            <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:globalBindings>
    </xs:appinfo>
</xs:annotation>


<xs:element name="getCountryRequest">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="name" type="xs:string" />
        </xs:sequence>
    </xs:complexType>
</xs:element>


<xs:element name="getCountryResponse">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="country" type="tns:country" />
        </xs:sequence>
    </xs:complexType>
</xs:element>

<xs:complexType name="country">
    <xs:sequence>
        <xs:element name="name" type="xs:string" />
        <xs:element name="population" type="xs:int" />
        <xs:element name="capital" type="xs:string" />
        <xs:element name="foundation" type="xs:date" />
        <xs:element name="currency" type="tns:currency" />
    </xs:sequence>
</xs:complexType>

[...]

It is also needed to add the -Djavax.xml.accessExternalSchema=all parameter on JVM when you run the maven builds.

The @vadim answer worked for me with a few additional details...

I was using spring boot 1.5.3 and the 2.3.1 version of the jaxb2-maven-plugin, and in that case I had to declare my xjb file as follows:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jaxb2-maven-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>xjc</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <packageName>...</packageName>
        <sources>
            <source>src/main/resources/file.xsd</source>
        </sources>
        <xjbSources>
            <xjbSource>src/main/resources/file.xjb</xjbSource>
        </xjbSources>
        <addGeneratedAnnotation>true</addGeneratedAnnotation>
        <locale>es</locale>
    </configuration>
</plugin>

In my case the xjb file content was:

<jaxb:bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema"
               xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" 
               jaxb:version="2.0"
               xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
               jaxb:extensionBindingPrefixes="xjc">
  <jaxb:globalBindings>
    <jaxb:serializable uid="1"/>
    <jaxb:javaType name="java.util.Date" xmlType="xsd:dateTime"
        parseMethod="package.path.bind.DataTypeConverter.parse"
        printMethod="package.path.bind.DataTypeConverter.print"/>
  </jaxb:globalBindings>
</jaxb:bindings>

And the DataTypeConverter content was:

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

public class DataTypeConverter {

    public static Date parse(String isoFormatDatetime) {
        return DatatypeConverter.parseDateTime(isoFormatDatetime).getTime();
    }
    public static String print(Date date) {
        return DatatypeConverter.printDateTime(toCalendar(date));
    }

    private static Calendar toCalendar(Date date){
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal;
    }
}

Hope this helps someone!! :)

This is probably a bit of a hack, but it works.

After generating your code with wsimport, you can do a find and replace in files, replacing all references to XmlGregorianCalendar with java.util.Date. JAXB will happily do all the processing for you and automagically do the conversions. No adapters needed. I haven't ran into any problems using this method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM