cxf-codegen-plugin port to Gradle

user447607 picture user447607 · Jan 22, 2016 · Viewed 10.3k times · Source

I'm trying to replicate what this plug-in does in Gradle. If I execute:

./wsdl2java -encoding UTF-8 -d /src/target/generated-sources/cxf -fe jaxws21
-sn UserSoapServicePorts -faultSerialVersionUID 1 -xjc-Xannotate 
-p http:... -p urn:... -p urn:... -p urn:... -p urn:h... -p urn:... 
-p urn:... -p urn:... 
-verbose /src/xmlTemp/user-soap-v1.wsdl 

...then I get:

an 22, 2016 3:51:05 PM org.apache.cxf.wsdl11.WSDLServiceBuilder checkForWrapped
INFO: Operation {urn:stuff:wsdl:person:v1}doSomething cannot be unwrapped, input message must reference global element declaration with same localname as operation

As far as I can tell, though the lines are identical. Any ideas what might be wrong?

Answer

bartolom picture bartolom · Mar 1, 2018

This answer is similar to the approach from Stefan K but works with Java 10 and Gradle 4.6 and does approximately the same as the Maven plugin cxf-codegen-plugin.

This solution builds upon the Blog post Generated Files in Gradle from mooregreatsoftware.com from the year 2013. It differs because

  • it avoids a build script dependency on commons-io:commons-io by implementing a very simple TeeOutputStream inline in Groovy
  • it is altered to work with Java 9, 10 and potentially 11.

One of the main motivations is JEP 320: Remove the Java EE and CORBA Modules which is scheduled for Java 11. There are ways to make this work with Java 9 and Java 10 by using things like --add-modules java.se.ee but JEP 320 states:

Since standalone versions of the Java EE technologies are readily available from third-party sites, such as Maven Central, there is no need for the Java SE Platform or the JDK to include them.

There are two code listings here, the first is a more compact code that does the work. The second code listing is the same code but with annotations and commented out transitive dependencies which you might want to override.

Shorter Version

plugins {
  id 'java'
  id 'project-report'
}

repositories {
  jcenter()
}

sourceCompatibility = 10
targetCompatibility = 10

configurations {
  wsdl2java
}

dependencies {
  compile 'org.apache.cxf:cxf-rt-frontend-jaxws:3.2.2'
  compile 'org.apache.cxf:cxf-rt-transports-http:3.2.2'

  compile 'javax.xml.ws:jaxws-api:2.3.0'
  compile 'javax.jws:jsr181-api:1.0-MR1'
  compile 'javax.xml.bind:jaxb-api:2.3.0'
  compile 'javax.activation:javax.activation-api:1.2.0'
  compile 'javax.annotation:javax.annotation-api:1.3'

  wsdl2java 'javax.xml.bind:jaxb-api:2.3.0'
  wsdl2java 'com.sun.xml.bind:jaxb-ri:2.3.0'
  wsdl2java 'com.sun.xml.bind:jaxb-xjc:2.3.0'
  wsdl2java 'com.sun.xml.bind:jaxb-core:2.3.0'
  wsdl2java 'com.sun.xml.bind:jaxb-impl:2.3.0'

  wsdl2java 'javax.activation:javax.activation-api:1.2.0'
  wsdl2java 'javax.annotation:javax.annotation-api:1.3'
  wsdl2java 'javax.xml.ws:jaxws-api:2.3.0'
  wsdl2java 'javax.jws:jsr181-api:1.0-MR1'

  wsdl2java 'org.apache.cxf:cxf-tools-wsdlto-core:3.2.2'
  wsdl2java 'org.apache.cxf:cxf-tools-wsdlto-frontend-jaxws:3.2.2'
  wsdl2java 'org.apache.cxf:cxf-tools-wsdlto-databinding-jaxb:3.2.2'
}

def wsdl2java = task generateJavaFromWsdl(type: JavaExec) {
  String wsdl = 'src/main/resources/some.wsdl'
  String genSrcDir = "${projectDir}/build/generated-sources/cxf-ws"

  inputs.file wsdl
  outputs.dir genSrcDir

  classpath configurations.wsdl2java
  main "org.apache.cxf.tools.wsdlto.WSDLToJava"

  args '-encoding', 'UTF-8', '-d', genSrcDir, wsdl

  OutputStream baos = new ByteArrayOutputStream()
  errorOutput = new OutputStream() {
    void write(int b) {System.err.write(b); baos.write(b) }  
    void flush() { System.err.flush(); baos.flush() }
    void close() { System.err.close(); baos.close() }
  }

  doLast {
  def str = baos.toString()
  if (str.contains('Usage : wsdl2java') || str.contains('WSDLToJava Error')) {
  throw new TaskExecutionException(tasks[name], 
  new IOException('Apache CXF WSDLToJava has failed. Please see System.err output.'))
  }
  }
}
compileJava.dependsOn += wsdl2java
sourceSets.main.java.srcDirs = ['src/main/java', 'build/generated-sources/cxf-ws']

Commented Version

plugins {
  id 'java'
  id 'project-report' // really useful to find out what gets pulled in transitively
}

repositories {
  jcenter()
}

// works with 1.8, 9, 10 and should be working with 11.
sourceCompatibility = 10
targetCompatibility = 10

configurations {
  wsdl2java
}

dependencies {
  compile 'org.apache.cxf:cxf-rt-frontend-jaxws:3.2.2'
  compile 'org.apache.cxf:cxf-rt-transports-http:3.2.2'

  compile 'javax.xml.ws:jaxws-api:2.3.0'
  compile 'javax.jws:jsr181-api:1.0-MR1'
  compile 'javax.xml.bind:jaxb-api:2.3.0'

  //
  // You might have these already imported due to other dependencies, but
  compile 'javax.activation:javax.activation-api:1.2.0'
  compile 'javax.annotation:javax.annotation-api:1.3'

  // ===== Apache CXF dependencies for the command line generation of java files
  //
  // http://openjdk.java.net/jeps/320
  // this JEP lists out exactly which dependencies are required to avoid using 
  // deprecated Java EE modules.

  //
  // JAXB dependencies that Apache CXF cxf-tools-wsdlto-databinding-jaxb uses directly
  // we list them here all so we have a single version 2.3.0 among all of them
  wsdl2java 'javax.xml.bind:jaxb-api:2.3.0'
  wsdl2java 'com.sun.xml.bind:jaxb-ri:2.3.0'
  wsdl2java 'com.sun.xml.bind:jaxb-xjc:2.3.0'
  wsdl2java 'com.sun.xml.bind:jaxb-core:2.3.0'
  wsdl2java 'com.sun.xml.bind:jaxb-impl:2.3.0'

  //
  // Other stuff that Apache CXF assume to be available from the JDK    
  wsdl2java 'javax.activation:javax.activation-api:1.2.0'
  wsdl2java 'javax.annotation:javax.annotation-api:1.3'
  wsdl2java 'javax.xml.ws:jaxws-api:2.3.0'
  wsdl2java 'javax.jws:jsr181-api:1.0-MR1'

  //
  // This is the big lazy solution and it puts the whole jaxws-ri stack on the classpath
  // As this is just the isolated classpath for wsdl2java you might not care.
  // This might be useful when you have missing dependencies with the above reduceded
  // list of dependencies. the Gradle plugin "project-report" has a task "projectReport"
  // that can really help
  //wsdl2java('com.sun.xml.ws:jaxws-ri:2.3.0') {
    //
    // this dependency is broken in 2.3.0. This articaft is simply not on mavenCentral
    // or jcenter. It looks like the correct one would be
    // 'org.eclipse.persistence:commonj.sdo:2.1.1' but we are not in the postion 
    // to change this. As we are not interested in any JPA integration anyways we
    // just skip it for now. 
    //exclude group: 'commonj.sdo', module: 'commonj.sdo'
  //}

  wsdl2java 'org.apache.cxf:cxf-tools-wsdlto-core:3.2.2'
  wsdl2java 'org.apache.cxf:cxf-tools-wsdlto-frontend-jaxws:3.2.2'
  wsdl2java 'org.apache.cxf:cxf-tools-wsdlto-databinding-jaxb:3.2.2'
}

//
// there is no real Gradle plugin here, we rather use Gradle's build in task JavaExec
// which is the Gradle way to call an external java program.
def wsdl2java = task generateJavaFromWsdl(type: JavaExec) {
  String wsdl = 'src/main/resources/some.wsdl'
  String genSrcDir = "${projectDir}/build/generated-sources/cxf-ws"

  inputs.file wsdl
  outputs.dir genSrcDir

  classpath configurations.wsdl2java
  main "org.apache.cxf.tools.wsdlto.WSDLToJava"

  // you can add any of the Apache CXF command line parameters here
  // http://cxf.apache.org/docs/wsdl-to-java.html
  args '-encoding', 'UTF-8', '-d', genSrcDir, wsdl

  // you can set jvmArgs as well. F.i. proxy
  //jvmArgs "-Dhttp.proxyHost=10.10.10.10", "-Dhttp.proxyPort=8080"

  OutputStream baos = new ByteArrayOutputStream()
  errorOutput = new OutputStream() {
    // extrem simplified TeeOutputStream to avoid dependency on Apache commons-io
    void write(int b) {System.err.write(b); baos.write(b) }  
    // no need to call flush and close on a ByteArrayOutputStream, but lets be safe
    void flush() { System.err.flush(); baos.flush() }
    void close() { System.err.close(); baos.close() }
  }

  // We inspect the collected logging an throw an TaskExecutionException if necessary. 
  doLast {
    String str = baos.toString()
    if (str.contains('Usage : wsdl2java') || str.contains('WSDLToJava Error')) {
      throw new TaskExecutionException(tasks[name], 
        new IOException('Apache CXF WSDLToJava has failed. Please see System.err output.'))
    }
  }
}
// we hook the custom task wsdl2java into the Gradle tasks graph / life cycle
compileJava.dependsOn += wsdl2java

// usually we want to access the generated code in the main source set and IDE's
sourceSets.main.java.srcDirs = ['src/main/java', 'build/generated-sources/cxf-ws']