【问题标题】:Replacing date of type XmlGregorianCalendar generated by wsdl to java.util.Date?将wsdl生成的XmlGregorianCalendar类型的日期替换为java.util.Date?
【发布时间】:2017-03-25 18:36:30
【问题描述】:

我正在开发一个应用程序,在该应用程序中,我们使用 Spring Web 服务通过 wsdl 生成的文件调用第三方 SAP 系统。

其中一个使用 wsdl 通过 ws 导入生成的文件具有“XMLGregorianCalendar”类型的日期属性,作为响应,我们得到相应字段的空值。

我想将日期从 XmlGregorianCalendar 转换为 java.util.Date。

已转介:how replace XmlGregorianCalendar by Date? 但无法通过 wsdl 提供适当的 xjb 绑定。

如果有人可以建议转换 wsdl 生成的日期,那将有很大帮助..... 提前致谢 ! 舒驰

【问题讨论】:

标签: java date wsdl


【解决方案1】:

WSDL 没有处理 xjb。 xjb 用于作为 -b 参数传递的 xjc 编译器。 即

xjc -b <file>

文档:Customizing JAXB Binding

如果您使用 Maven 插件来生成您的 JAXB Java 类,它们中的任何一个都具有绑定配置,即

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

<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>

等等……

xjb 因为它很简单:

<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>

如您所见,它定义了从 xsd:dateTime、xsd:date 和 xsd:time 类型到 java.util.Calendar 的转换。

我不推荐使用 java.util.Date。日期处理有很多麻烦(尤其是不同的时区)。 最好使用 java.util.Calendar。日历更容易处理,JDK 中有默认的转换器实现:

javax.xml.bind.DatatypeConverter

但是,如果您仍然想使用 java.Util.Date,您需要拥有自己的小型转换器,其中包含两个静态方法“parse”和“print”,然后在 xjb 中设置它。即

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);
    }
}

您在 xjb 中的转化将如下所示:

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

【讨论】:

  • “WSDL 没有处理 xjb。”不知道你的意思是什么。 wsimport 调用 xjc。 wsimport 接受传递给 xjc 的 -b bindingsfile 参数。
  • WSDL - Web 服务定义语言。而已。当 JAXB 生成 Java 类时,xjb 仅特定于 Java 中的一种实现 - JAXB。 Java 有更多的实现:Axis、Axis2、XBeans 和其他一些...... WSDL 是每个人都可以实现的。 C、C++、C# 开发人员对 xjb 毫无概念。甚至那些使用 Axis2 的人。 :)
  • 啊,我明白了。您的观点是 WSDL 本身是语言中立的。
  • 是的,完全正确。实际上我第一次想知道,为什么 JAXB 默认使用 XmlGregorianCalendar 而不仅仅是 Calendar。 :)
  • 因为 XML 模式有许多日期时间类型:dateTime、日期、时间、gYear、gYearMonth、gMonth、gMonthDay、gDay。日历只能代表完整的日期时间,而不是部分信息。
【解决方案2】:

@vadim 的回答对我有用,还有一些额外的细节......

我使用的是 spring boot 1.5.3 和 jaxb2-maven-plugin 的 2.3.1 版本,在这种情况下,我必须如下声明我的 xjb 文件:

<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>

在我的例子中,xjb 文件的内容是:

<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>

DataTypeConverter 的内容是:

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;
    }
}

希望这对某人有所帮助! :)

【讨论】:

  • 是的,你是对的。不同的插件使用不同的配置设置将 xjb 提供给 xjc 编译器。您使用 jaxb2-maven-plugin 直接从 XSD 生成 JAXB 类,而不是从 WSDL 生成 Web 服务类。当我需要来自 XSD 的类时,我也会使用它。但是对于 WSDL,这取决于我需要使用什么 Web 服务实现。例如在我的例子中是 CXF...
  • 是的,这就是我投票赞成你的答案的原因,但也许有类似情况的人会发现这个规范很有用:)
【解决方案3】:

我已将 bean 的 java 类型从 XMLGregorianCalendar 更改为直接在 xsd 的合同上添加 jaxb 的配置。

我已经这样做了,注意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>

[...]

在运行maven构建时,还需要在JVM上添加-Djavax.xml.accessExternalSchema=all参数。

【讨论】:

    【解决方案4】:

    这可能有点小技巧,但它确实有效。

    使用 wsimport 生成代码后,您可以在文件中进行查找和替换,将所有对 XmlGregorianCalendar 的引用替换为 java.util.Date。 JAXB 很乐意为您完成所有处理并自动进行转换。无需适配器。使用这种方法我没有遇到任何问题。

    【讨论】:

    • 如果您对此投了反对票,至少有礼貌地评论一下原因。此方法适用于日期和日历。
    • 我没有投反对票,但这里的主要缺点是:“生成后......在文件中查找和替换”。这意味着您需要生成一次类,然后将它们放在源中的某个位置,然后不要触摸它们。当 XSD 发生变化时,它需要一遍又一遍地进行。它将构建过程从 Maven、Jenkins 等提供的任何自动化中剔除。Xjb 正是用于该目的。 JAXB 类生成项目不需要保存生成的类。它们可以根据需要多次再生。所有使用它们的代码/项目只需要对该项目的 Maven 依赖即可。
    • 没错,我一直发现经常需要修改生成的代码,尤其是 jaxb
    • 我已经不得不在糟糕的 API 生成的客户端代码中使用运行时异常替换检查异常。我正在使用 groovy-maven-plugin 在生成和编译之间运行任意代码。我会为这个日期做这个建议:它看起来比搞乱 xjb 文件更不生硬!
    【解决方案5】:

    您必须创建一个自定义数据类型适配器并添加到绑定文件中。

     <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>
    

    类 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);
        }
    }
    

    【讨论】:

    • 感谢您的回复......因为我是新手,请您帮助我如何将此 globalBindings 与 wsdl 相关联,以便从 thirdPartySap 返回的日期映射到 java。 util.Date 尽管 XMLGregorianCalendar Date 类型。
    • 您必须将绑定文件作为参数传递给 wsdl2java 实用程序。 -b 绑定.xml
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-22
    • 1970-01-01
    • 1970-01-01
    • 2010-10-24
    • 2019-08-20
    • 1970-01-01
    • 2011-04-10
    相关资源
    最近更新 更多