Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resolving conflicts when generating code with CXF and wsdl2java

I'm struggling with some conflicts during code generation from a bunch of WSDL files using wsdl2java via the cxf-codegen-plugin with Maven. The WSDLs declare different APIs of the same system, and the generated code has some amount of overlap (especially with the model classes). The external system and the WSDLs come from a third party and are therefore not controlled by us.

The first problem I have is a naming conflict in one of the resulting ObjectFactory classes caused by one of the WSDLs. It defines a complexType with the name Foo that contains an element with the name Status, and it also defines a element with the name FooStatus. When generating the code, JAXB throws a fit because the ObjectFactory would have two factory methods with the name createFooStatus(...) and I end up with an exception during runtime. I've tried providing the option -autoNameResolution to wsdl2java with no avail. I've looked at "Two declarations cause a collision in the ObjectFactory class" and "Applying external JAXB binding file to schema elements imported from WSDL", and based on those I've written an external binding file that renames one of the factory methods. I use SCD instead of XPath in the binding file as shown in the latter link, because I had the same problem with XPath as the author. This works, but only if I process the WSDL files individually and apply the binding file only to the WSDL that causes the conflict. The Maven configuration looks like this:

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

Now, if I do this I end up with another problem, because the generated code from the different WSDL files uses the same package structure. What this means in practice is that the ObjectFactory classes get overridden when processing subsequent WSDL files, meaning that only the one generated from the last WSDL will exist after the plugin execution. I know that I could change the target package structure, but the code generated from the different WSDLs has a lot of overlap and it would feel silly to duplicate it. I've also tried using the -keep wsdl2java option, but that doesn't seem to do anything (or at least the ObjectFactory classes still get overridden). My understanding is that the solution to this would be to process all of the WSDLs in one go with a Maven configuration like this (showing only the configuration section, all else stays the same):

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

However, this results in a com.sun.istack.SAXParseException2, saying that my SCD expression doesn't match any schema component (since the schema component exists only in one of the WSDLs).

I can get the result I want if I modify the WSDL file itself and use the latter Maven configuration without the binding file. By doing this, the resulting ObjectFactory is a merge from the ones that would be created when processing the WSDLs individually with the first Maven config. However, I'd rather not do that, but instead would like to manage this with an external binding file. How should I go about solving this? Can I write/apply the binding file so that no exception is raised if the matching schema component is not found? Or can I process the WSDLs individually and not overwrite the ObjectFactory classes? Or do I just have to suck it up and either generate the code from different WSDLs to different packages or edit the WSDL files themselves? Just in case it matters, my current binding file looks like this (the WSDLs are located inside my project in the same directory with the binding file):

<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>
like image 616
Markus Yrjölä Avatar asked Mar 15 '14 14:03

Markus Yrjölä


1 Answers

I eventually solved this myself after some more googling around and reading forum posts. I managed to write the external binding file using XPath (instead of SCD) in a way that only targets the node I'm interested in without giving an error when processing the other WSDL files. The main source of confusion that initially prevented me from targeting nodes in the WSDL with XPath was the similar XML schemas of the JAXB and JAXWS namespaces (both define the element 'bindings', and most tutorials I've seen used the JAXB version while here I had to use the JAXWS version). The resulting binding file looks like this:

<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>
like image 184
Markus Yrjölä Avatar answered Nov 03 '22 19:11

Markus Yrjölä