【问题标题】:JAXB workaround for Chameleon XSD imports?Chameleon XSD 导入的 JAXB 解决方法?
【发布时间】:2011-04-27 22:02:07
【问题描述】:

这是我的第一个问题,所以请温柔;)

我遇到了一个奇怪的问题。基本上我得到了三个 XSD 定义,如下所示:

PartA.xsd
targetNameSpace="PartA"
include="PartB.xsd"

PartB.xsd
<!-- no namespace definition!!! -->

PartC.xsd
targetNameSpace="PartC"
inlude="PartB.xsd"
import="PartA.xsd"

通过 JAXB 将 PartC 绑定到 Java 类时弹出错误:

  • 同名“b.exampleType”的类/接口已在使用中。使用类自定义来解决此冲突。
  • 这个令人困惑的错误很可能发生,因为该架构使用了一种称为“变色龙架构”的技术,这会导致将单个定义多次加载到不同的命名空间中。有关更多信息,请参阅 http://forums.java.net/jive/thread.jspa?threadID=18631

通过链接,我发现实际的错误在于 PartB,它没有命名空间声明!此方法称为 Chameleon SchemaPartB 中定义的类型将采用导入 XSD 的命名空间。

所以在我的例子中,同一类型有两个命名空间:

  1. “A部分”
  2. “C部分”

这就是 JAXB 崩溃的地方。我还没有找到正确绑定 PartC 的方法。而且(让事情变得棘手)我有机会更改原始 XSD 定义!

以前有没有人遇到过这种现象或类似的事情并有有效的解决方法?

【问题讨论】:

    标签: java xml xsd jaxb


    【解决方案1】:

    【讨论】:

    • 感谢您的链接,但您是对的,它不是很详细。而且由于我对架构没有写访问权限,所以我被卡住了。 ...虽然,也许我可以与架构作者争论“在其他一些情况下,变色龙架构可以被认为是一个糟糕的架构设计,因为它在许多地方重复了定义。”点。
    【解决方案2】:

    我遇到了同样的问题,谷歌搜索让我来到了这里。 你的问题很详细,我找到了答案, 我所做的是将命名空间放入 PartB.xsd 并使用 XJC 生成 java 类。 我添加了以下内容:

    xmlns:ns="http://www.myCompany.com/2009/01/CustSchema" targetNamespace="http://www.myCompany.com/2009/01/CustSchema"

    【讨论】:

    • 也遇到了同样的问题,发现我的答案只是阅读了这个问题本身,检查了所有三个 xsd 中的命名空间,然后将缺少的命名空间放在 xsd 和 bingo 之一中!
    【解决方案3】:

    我在使用 wsdl2java 时遇到了同样的问题:

    WSDLToJava 错误:由 JAXB 引发:具有相同的类/接口 名称“Respuesta”已被使用。使用类自定义 解决这个冲突。

    但这question 为我指明了正确的方向。 使用 CFX 中的 wsdl2java,您可以使用 binding.xml 文件自定义元素绑定到类的方式。 例如:

    /Applications/apache-cxf-2.7.13/bin/wsdl2java -b ./src/main/resources/binding.xml -V -d src/main/java -compile -classdir target/classes  http://someurl.wsdl
    

    关键是在 binding.xml 中解释为某些 xsd 元素使用一个特定的 className 来命名以避免冲突:

    <jxb:bindings xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" version="2.1">
    
      <jxb:bindings schemaLocation="./someXsdFile.xsd">
        <!-- Rename the respuesta class to resolve a naming conflict with other Respuesta element already defined-->
        <jxb:bindings node="//xs:element[@name='respuesta']/xs:complexType">
          <jxb:class name="Respuesta2" />
        </jxb:bindings>
      </jxb:bindings>
    </jxb:bindings>
    

    希望这对使用 wsdl2java 的下一个人有帮助。我认为其他工具应该允许类似的方法来解决这个问题。

    【讨论】:

      【解决方案4】:

      此问题有一种解决方法。更具体地说,您需要做的是:

      1.为PartB.xsd(无命名空间定义)定义代理架构(PartB_proxy.xsd)并指定临时命名空间(例如PartB强>):

      <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" xmlns="PartB"
              targetNamespace="PartB">
      <xsd:include schemaLocation="partB.xsd"/>
      

      2.准备绑定文件(对于大型架构,此步骤可以通过生成剧集文件来自动化 - 我的文章中的更多详细信息 - 我在本文末尾附加了链接) - 需要此步骤以避免生成重复的类对于 PartB 架构(默认情况下,将为 PartA 和 PartC 架构/java 包生成来自 PartB 架构的重复类):

      <bindings version="2.1" xmlns="http://java.sun.com/xml/ns/jaxb"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema">
          <bindings scd="x-schema::partA" xmlns:partA="PartA">
              <bindings scd="~partA:SomeType1">
                  <class ref="SomeType1"/>
              </bindings>
              <bindings scd="~partA:SomeType2">
                  <class ref="SomeType2"/>
              </bindings>
          </bindings>
          <bindings scd="x-schema::partC" xmlns:partC="PartC">
              <bindings scd="~partC:SomeType1">
                  <class ref="SomeType1"/>
              </bindings>
              <bindings scd="~partC:SomeType2">
                  <class ref="SomeType2"/>
              </bindings>
          </bindings>
      </bindings>
      

      3.使用 XJC 生成 JAXB 类,例如 Gradle 任务(我使用的是 Moxy 实现,但您可以使用 JDK 8 中的默认 XJC 生成器或独立 JAXB 库用于更新的 JDK 版本):

      task generateExampleChameleonSourcesWithMoxy(type: JavaExec) {
      classpath = configurations.moxy
      main = 'org.eclipse.persistence.jaxb.xjc.MOXyXJC'
      args '-b'
      args 'src/main/resources/example/chameleon/bindings.xml'
      args '-d'
      args 'src/main/generated'
      args 'src/main/resources/example/chameleon/PartA.xsd'
      args 'src/main/resources/example/chameleon/PartB_proxy.xsd'
      args 'src/main/resources/example/chameleon/PartC.xsd'
      

      }

      4.从 package-info.java 中删除为 partB 模式生成的代理命名空间(partB):

      javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
      package partB;
      

      5.最后,您可以使用 Default Namespace Remapping 技术编组和解组这些 XML 文档:

      • 为没有命名空间的类型定义默认命名空间:

        com.sun.xml.internal.bind.defaultNamespaceRemap 属性(JDK JAXB >=JDK 1.8) com.sun.xml.bind.defaultNamespaceRemap 属性(外部 JAXB JDK 1.9+)

      • 照常执行编组/解组

      这是负责该操作的代码(JDK 1.8):

      //Initialize JaxbContext
      Map<String, String> properties = new HashMap<>();
      properties.put("com.sun.xml.internal.bind.defaultNamespaceRemap", "partC");
      JAXBContext jaxbContext = JAXBContext.newInstance(new Class[]{SomeType1.class}, properties);
      //Unmarshall Message object file from example XML
      Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
      Object messageObject =     unmarshaller.unmarshal(getClass().getResourceAsStream("/example/chameleon/Division.xml"));
      //Marshall message object back into XML
      ByteArrayOutputStream xmlMessageOS = new ByteArrayOutputStream();
      Marshaller marshaller = jaxbContext.createMarshaller();
      marshaller.marshal(messageObject, xmlMessageOS);
      System.out.println(xmlMessageOS.toString());
      //Validate output XML with schema
      InputStream xmlInputStream = new     ByteArrayInputStream(xmlMessageOS.toByteArray());
      Source xmlSource = new StreamSource(xmlInputStream);
      SchemaFactory schemaFactory =         SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
      Schema schema =     schemaFactory.newSchema(getClass().getResource("/example/chameleon/PartC.xsd"));
      Validator validator = schema.newValidator();
      validator.validate(xmlSource);`
      

      不幸的是,对于来自 PartAPartC 命名空间的 JAXB 对象,您必须使用不同的 JAXB 上下文。这是必需的,因为 JAXB 默认命名空间重新映射属性是根据 JAXB 上下文设置的 - 这样 JAXB 编组器/解组器就知道如何处理没有定义命名空间的 POJO 对象(PartB)。 不过,我认为这不是问题,因为通常所有 JAXB 上下文都被初始化一次 - 在应用程序启动期间(在单例中)。

      总而言之,上述解决方法允许您使用 JAXB 编组/解组 XML 文档,而无需修改变色龙模式。代理 XSD 文件仅在开始时使用 - 用于生成 JAXB 对象 (XJC) 的过程。编组/未编组的 XML 文档仍然符合原始模式。这种技术特别有用,如果您不允许修改模式。我正在为http://www.iata.org定义的18.1版本中的只读NDC标准(模式集)处理这个问题。

      我写过一篇关于该主题的文章:如何在 JAXB 中处理 Chameleon 命名空间设计。你会在这里找到它:https://medium.com/@pziobron/how-to-deal-with-chameleon-namespace-design-in-jaxb-e36bcc03767d。希望您会发现它很有用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-29
        • 1970-01-01
        • 1970-01-01
        • 2015-06-28
        • 1970-01-01
        • 2021-11-20
        相关资源
        最近更新 更多