使用CXF和wsdl2java生成代码时解决冲突

时间:2014-03-15 14:53:27

标签: java web-services maven jaxb wsdl

我在使用wsdl2java通过带有Maven的cxf-codegen-plugin从一堆WSDL文件生成代码时遇到了一些冲突。 WSDL声明了同一系统的不同API,并且生成的代码有一些重叠(特别是对于模型类)。外部系统和WSDL来自第三方,因此不受我们控制。

我遇到的第一个问题是由一个WSDL导致的一个ObjectFactory类中的命名冲突。它定义了一个名为Foo的complexType,其中包含名为Status的元素,并且还定义了一个名为FooStatus的元素。生成代码时,JAXB会抛出一个拟合,因为ObjectFactory将有两个名为createFooStatus(...)的工厂方法,并且在运行时期间最终会出现异常。我试过向wsdl2java提供选项-autoNameResolution但没有用。我查看了"Two declarations cause a collision in the ObjectFactory class""Applying external JAXB binding file to schema elements imported from WSDL",并根据我编写的外部绑定文件重命名了一种工厂方法。我在绑定文件中使用SCD而不是XPath,如后一个链接所示,因为我和XPath的问题与作者有同样的问题。这是有效的,但前提是我单独处理WSDL文件并仅将绑定文件应用于导致冲突的WSDL。 Maven配置如下所示:

<plugin>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-codegen-plugin</artifactId>
  <version>3.0.0-milestone1</version>
  <executions>
    <execution>
      <id>generate-proxies</id>
      <phase>generate-sources</phase>
      <configuration>
        <wsdlOptions>
          <wsdlOption>
            <wsdl>${basedir}/First.wsdl</wsdl>
            <bindingFiles>
              <bindingFile>${basedir}/bindings.xml</bindingFile>
            </bindingFiles>
          </wsdlOption>
          <wsdlOption>
            <wsdl>${basedir}/Second.wsdl</wsdl>
          </wsdlOption>
          <wsdlOption>
            <wsdl>${basedir}/Third.wsdl</wsdl>
          </wsdlOption>
          ... More wsdlOption declarations ...
        </wsdlOptions>
      </configuration>
      <goals>
        <goal>wsdl2java</goal>
      </goals>
    </execution>
  </executions>
</plugin>

现在,如果我这样做,我最终会遇到另一个问题,因为来自不同WSDL文件的生成代码使用相同的包结构。这在实践中意味着在处理后续WSDL文件时会覆盖ObjectFactory类,这意味着在插件执行后只存在从最后一个WSDL生成的类。我知道我可以更改目标包结构,但是从不同的WSDL生成的代码有很多重叠,复制它会感觉很傻。我也尝试使用-keep wsdl2java选项,但似乎没有做任何事情(或者至少ObjectFactory类仍然被覆盖)。我的理解是,对此的解决方案是使用像这样的Maven配置一次性处理所有WSDL(仅显示配置部分,所有其他内容保持不变):

<configuration>
  <defaultOptions>
    <bindingFiles>
      <bindingFile>${basedir}/bindings.xml</bindingFile>
    </bindingFiles>
  </defaultOptions>
  <wsdlRoot>${basedir}</wsdlRoot>
  <includes>
    <include>*.wsdl</include>
  </includes>
</configuration>

但是,这导致com.sun.istack.SAXParseException2,表示我的SCD表达式与任何模式组件都不匹配(因为模式组件仅存在于其中一个WSDL中)。

如果我修改WSDL文件并使用后面没有绑定文件的Maven配置,我可以得到我想要的结果。通过执行此操作,生成的ObjectFactory是与使用第一个Maven配置单独处理WSDL时将创建的合并。但是,我宁愿不这样做,而是想用外部绑定文件来管理它。我该如何解决这个问题?我可以编写/应用绑定文件,以便在找不到匹配的模式组件时不会引发异常吗?或者我可以单独处理WSDL而不是覆盖ObjectFactory类吗?或者,我是否只需要将其填充并从不同的WSDL生成代码到不同的包或自己编辑WSDL文件?为了防止重要,我当前的绑定文件看起来像这样(WSDL位于我的项目中与绑定文件在同一目录中):

<bindings scd="x-schema::tns" xmlns:tns="NamespaceOfFoo" xmlns="http://java.sun.com/xml/ns/jaxb" version="2.1">
  <bindings scd="tns:FooStatus">
    <factoryMethod name="FooStatusType"/>
  </bindings>
</bindings>

1 个答案:

答案 0 :(得分:5)

我最终在谷歌搜索并阅读论坛帖后解决了这个问题。我设法使用XPath(而不是SCD)编写外部绑定文件,其方式仅针对我感兴趣的节点,而不会在处理其他WSDL文件时出错。最初阻止我使用XPath定位WSDL中的节点的主要混淆源是JAXB和JAXWS命名空间的类似XML模式(两者都定义了元素'绑定',我见过的大多数教程都使用了JAXB版本)我不得不使用JAXWS版本)。生成的绑定文件如下所示:

<jaxws:bindings xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
                xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
                xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
                wsdlLocation="First.wsdl"
                version="2.1">
  <jaxws:bindings node="wsdl:definitions/wsdl:types/xsd:schema/xsd:element[@name='FooStatus']">
    <jaxb:factoryMethod name="FooStatusType"/>
  </jaxws:bindings>
</jaxws:bindings>