【问题标题】:How to make jaxb plugin use OffsetDateTime如何让 jaxb 插件使用 OffsetDateTime
【发布时间】:2018-02-19 10:28:19
【问题描述】:

我们有一个带有xs:dateTime 字段的xsd。这是我们内部的 API,我们可以保证始终包含偏移数据,因此它与 ISO-8601 兼容。例如:

2016-01-01T00:00:00.000+01:00

目前,jaxb2 插件将xs:dateTime 映射到XMLGregorianCalendar 类型的字段。如何配置插件,使其使用OffsetDateTime

我不在乎解决方案是针对maven-jaxb2-pluginjaxb2-maven-plugin 还是cxf-codegen-plugin,我们会使用任何一个有效的解决方案。

【问题讨论】:

    标签: java java-time maven-jaxb2-plugin jaxb2-maven-plugin cxf-codegen-plugin


    【解决方案1】:

    jTextTime library 解决了这个问题。

    该库围绕 JDK8 OffsetXXX 日期/时间类,因为它们是 XML Schema 类型 datedateTimetime 的(唯一)自然等价物。它还处理differences between XML types and JSR-310 types,因为不幸的是没有一对一的匹配。

    这样使用:

    添加依赖:

    <dependency>
        <groupId>com.addicticks.oss</groupId>
        <artifactId>jtexttime</artifactId>
        <version> ... latest ...</version>
    </dependency>
    

    创建您的 XJC 绑定:

    创建一个名为src/main/xjb/jaxb-datetime-bindings.xjb 的文件,内容如下。 如果您使用的是 JAXB2 Maven 插件,那么插件会自动获取它。如果你正在使用另一个 Maven 插件,那么你必须告诉它在哪里可以找到这个文件。

    <?xml version="1.0" encoding="UTF-8"?>
        <!-- This file is automatically picked up by the jaxb2-maven-plugin
             if it lives in src/main/xjb                                -->
    <jxb:bindings   
            xmlns:jxb="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"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
            version="2.1">
    
        <jxb:globalBindings>
            <!-- Avoid having to work with XMLGregorianCalendar. 
                 Instead, map as follows:
    
                     XML dateTime   :   OffsetDateTime  
                     XML date       :   OffsetDateTime  (time value truncated)
                     XML time       :   OffsetTime                             -->
    
            <xjc:javaType adapter="com.addicticks.texttime.jaxb.OffsetDateTimeXmlAdapter"
                          name="java.time.OffsetDateTime" xmlType="xs:dateTime"/>
            <xjc:javaType adapter="com.addicticks.texttime.jaxb.OffsetDateXmlAdapter"
                          name="java.time.OffsetDateTime" xmlType="xs:date"/>
            <xjc:javaType adapter="com.addicticks.texttime.jaxb.OffsetTimeXmlAdapter"
                          name="java.time.OffsetTime" xmlType="xs:time"/>
    
        </jxb:globalBindings>
    
    </jxb:bindings>
    

    JAXB2 Maven 插件默认会拾取src/main/xjb/ 文件夹中的所有.xjb 文件,因此您不必在插件的配置中指定上述文件。

    项目的README 有更多关于如何使用该库的信息。

    【讨论】:

      【解决方案2】:

      您可以将jaxb2-maven-pluginjaxb-bindings 文件一起使用。

      首先我创建了一个odt.xsd 文件:

      <?xml version="1.0" encoding="UTF-8"?>
      <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <xsd:element name="teste" type="Teste" />
        <xsd:complexType name="Teste">
          <xsd:sequence>
            <xsd:element name="date" type="xsd:dateTime" minOccurs="1"
              maxOccurs="1" nillable="false"/>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:schema>
      

      然后我创建了一个jaxb-bindings.xjb 文件,它定义了date 字段的类型,以及从它转换到它的类:

      <jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" jaxb:version="2.0">
          <jaxb:bindings schemaLocation="odt.xsd">
              <jaxb:bindings node="//xsd:element[@name='date']">
                  <jaxb:javaType name="java.time.OffsetDateTime"
                   parseMethod="xsd.test.OffsetDateTimeAdapter.parse"
                   printMethod="xsd.test.OffsetDateTimeAdapter.print" />
              </jaxb:bindings>
              <jaxb:schemaBindings>
                  <jaxb:package name="xsd.test" />
              </jaxb:schemaBindings>
          </jaxb:bindings>
      </jaxb:bindings>
      

      该文件引用了xsd.test.OffsetDateTimeAdapter 类以及将OffsetDateTimeString 转换为String 的相应方法,因此我也创建了它:

      package xsd.test;
      
      import java.time.OffsetDateTime;
      
      public class OffsetDateTimeAdapter {
      
          public static OffsetDateTime parse(String value) {
              return OffsetDateTime.parse(value);
          }
      
          public static String print(OffsetDateTime value) {
              return value.toString();
          }
      }
      

      然后,我在pom.xml 中添加了插件的配置:

      <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>jaxb2-maven-plugin</artifactId>
          <executions>
              <execution>
                  <id>xjc</id>
                  <goals>
                      <goal>xjc</goal>
                  </goals>
              </execution>
          </executions>
          <configuration>
              <!-- The package of your generated sources -->
              <packageName>xsd.test</packageName>
              <sources>
                  <source>src/main/resources/odt.xsd</source>
              </sources>
              <xjbSources>
                  <xjbSource>src/main/resources/jaxb-bindings.xjb</xjbSource>
              </xjbSources>
          </configuration>
      </plugin>
      

      有了这个,我刚刚用mvn clean package 构建了项目,创建的jar 包含xsd.test 包中的生成文件。 Teste 类包含date 字段作为OffsetDateTime

      @XmlAccessorType(XmlAccessType.FIELD)
      @XmlType(name = "Teste", propOrder = {
          "date"
      })
      public class Teste {
      
          @XmlElement(required = true, type = String.class)
          @XmlJavaTypeAdapter(Adapter1 .class)
          @XmlSchemaType(name = "dateTime")
          protected OffsetDateTime date;
          // getter and setter
      }
      

      这样,date 字段使用自动生成的Adapter1(内部使用上面创建的xsd.test.OffsetDateTimeAdapter 类)映射到OffsetDateTime。从 xml 中解析日期的示例:

      ObjectFactory f = new ObjectFactory();
      JAXBContext context = JAXBContext.newInstance("xsd.test");
      Unmarshaller unmarshaller = context.createUnmarshaller();
      String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><ns2:teste xmlns:ns2=\"xsd.test\"><date>2016-01-01T00:00+01:00</date></ns2:teste>";
      JAXBElement<Teste> jaxElement = unmarshaller.unmarshal(new StreamSource(new ByteArrayInputStream(xml.getBytes())), Teste.class);
      OffsetDateTime odt = jaxElement.getValue().getDate();
      System.out.println(odt); // 2016-01-01T00:00+01:00
      

      并且在将日期编组为 xml 时,OffsetDateTime 会直接转换为 String,例如 2016-01-01T00:00+01:00


      另一种方法是使用命令行xjc,JDK自带:

      xjc src/main/resources/odt.xsd -d src/main/java/ -p xsd.test -b src/main/resources/jaxb-bindings.xjb
      

      这会在src/main/java 目录中的xsd.test 包中生成类。

      【讨论】:

      • 谢谢,这很好用。唯一的缺点是您必须枚举xjb 中的所有xsd:dateTime 元素。但这是次要的。
      • @LustigerAstronaut 不客气,很高兴为您提供帮助!也许您可以将绑定更改为node="//xsd:element[@type='xsd:dateTime']"(不过我还没有测试过)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-04
      • 2011-03-06
      • 2014-09-29
      • 1970-01-01
      • 2011-12-11
      • 1970-01-01
      • 2011-12-04
      相关资源
      最近更新 更多