17

我有一个像这样的绑定文件

<jxb:bindings version="2.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <jxb:bindings schemaLocation="example.xsd" node="/xs:schema">
    <jxb:schemaBindings>
        <jxb:package name="example" />
    </jxb:schemaBindings>
    <jxb:globalBindings>
        <jxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"
            parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime"
            printMethod="javax.xml.bind.DatatypeConverter.printDateTime" />
        <jxb:javaType name="java.util.Calendar" xmlType="xs:date"
            parseMethod="javax.xml.bind.DatatypeConverter.parseDate"
            printMethod="javax.xml.bind.DatatypeConverter.printDate" />
        <jxb:javaType name="java.util.Calendar" xmlType="xs:time"
            parseMethod="javax.xml.bind.DatatypeConverter.parseTime"
            printMethod="javax.xml.bind.DatatypeConverter.printTime" />
    </jxb:globalBindings>

  </jxb:bindings>
</jxb:bindings>

架构类在“示例”中生成(正确),但 XmlAdapters 在“org.w3._2001.xmlschema”中生成(错误)。我怎样才能解决这个问题?

4

5 回答 5

12

-p对于 Apache CXF用户,最简洁的方法是使用wsdl2java.

-p [wsdl-命名空间=]包名

指定零个或多个包名称以用于生成的代码。(可选)指定 WSDL 名称空间到包名称的映射。

在我们的例子中

-p http://www.w3.org/2001/XMLSchema=org.acme.foo

如果您使用 cxf-codegen-plugin,则只需添加另一对<extraarg>.

<plugin>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-codegen-plugin</artifactId>
    <version>${cxf.version}</version>
        [...]
    <extraarg>-p</extraarg>
    <extraarg>http://www.w3.org/2001/XMLSchema=org.acme.foo</extraarg>
        [...]
</plugin>

不需要 targetNamespace 指向保留的 XSD 命名空间,也不需要包罗万象的 jaxb 包绑定。

于 2014-02-13T18:34:19.397 回答
11

之所以在此处创建该org.w3._2001.xmlschema包,是因为 XJC 必须生成一个扩展类,该类javax.xml.bind.annotation.adapters.XmlAdapter又调用您的 parse/print 静态方法。出于某种原因,它将它们放入这个包中,而不是放在更有用的地方。

您还没有说您使用哪个 JAXB 实现,但是 JAXB RI 有一个javaType绑定自定义的扩展,它允许您XmlAdapter直接指定一个子类,而不是parseMethod/printMethod对。这消除了生成合成XmlAdapter桥类的需要。请参阅RI 文档了解如何执行此操作。

我想 EclipseLink/Moxy 有类似的东西,但我不确定 Java6 附带的 XJC 是否有能力(当 Sun 将它带入 JRE 时,似乎已经从 RI 中删除了一半有用的东西) .

于 2011-03-17T13:40:07.003 回答
10

使用 GlobalBinding 的更好方法是指定显式适配器,而不是使用此解析/打印对。例如,而不是以下内容:

<jaxb:javaType name="java.lang.Long" xmlType="xs:long"
                      parseMethod="com.mypackage.myclass.parseLong"
                  printMethod="com.mypackage.myclass.print"/>

相反,您应该:

<xjc:javaType name="java.lang.Long" xmlType="xs:long"
                  adapter="com.mypackage.LongAdapter"/>

记得为 xjc 添加命名空间:

xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
          jxb:extensionBindingPrefixes="xjc"

LongAdapter 类是这样的:

public class LongAdapter
extends XmlAdapter<String, Long>
{


public Long unmarshal(String value) {
    return your_util_class.parseLong(value);
}

public String marshal(Long value) {
    return your_util_class.print(value);
}

}

这样,由于您明确指定了适配器类,所以 jaxb 不会生成默认包名称为 org.w3._2001.xmlschema 的默认适配器。

避免使用默认包名 org.w3._2001.xmlschema 非常重要。举个例子,如果你有一个项目 A 和一个项目 B,并且它们都有一些架构和绑定。以旧的方式,它们都生成具有完全相同的全限定名称的适配器,例如 org.w3._2001.xmlschema.Adapter1。但是,此适配器可能用于项目 A 中的 Long 和项目 B 中的 Integer。然后,假设您有一个同时使用 A 和 B 的下游项目 C。现在问题变得令人讨厌。如果 C 需要使用 Adapter1,您无法预测使用的是来自 A 的 Long 或来自 B 的 Integer。然后,您的应用程序 C 可能会在一段时间内正常工作,但在某些其他情况下可能会以一种奇怪的方式失败。如果发生这种情况,类型异常将类似于:

org.w3._2001.xmlschema.Adapter1 is not applicable to the field type java.lang.Double...

Roy Truelove 提到的解决方案在我使用 maven-jaxb2-plugin 在我的环境中尝试时似乎不起作用,即使理论是正确的。

于 2016-08-26T08:56:09.210 回答
8

我也有这个问题,用这个解决了。

基本前提是您在 XJC 编译中包含一个具有以下内容的模式:

<schema xmlns="http://www.w3.org/2001/XMLSchema"
  targetNamespace="http://www.w3.org/2001/XMLSchema"
  xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
  jaxb:version="2.0">
  <annotation><appinfo>
    <jaxb:schemaBindings>
      <jaxb:package name="org.acme.foo"/>
    </jaxb:schemaBindings>
  </appinfo></annotation>
</schema>

然后,您将包名称调整为您希望放置生成的适配器的位置。XJC 将相信此模式是 W3C XML 模式本身的模式集的一部分,并将尊重其中的绑定。

于 2011-08-30T15:50:21.530 回答
0

对常见数据类型使用内置转换器。

<jxb:javaType name="java.lang.Integer" xmlType="xs:integer"              
parseMethod="javax.xml.bind.DatatypeConverter.parseInt"                  
printMethod="javax.xml.bind.DatatypeConverter.printInt" />
于 2018-06-27T20:44:44.747 回答