ciscoo / cxf-codegen-gradle

Gradle plugin to generate Java artifacts from WSDL
Apache License 2.0
26 stars 6 forks source link

wsdlList example needed #27

Closed guai closed 2 years ago

guai commented 2 years ago

Hi How do I properly port this maven snippet into gradle? I'm not sure what to do about a pair of wsdls in the wsdl-oms-to-java execution. Should I use wsdlList in this case?

<plugin>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-codegen-plugin</artifactId>
                <version>${apache.cxf.version}</version>
                <configuration>
                    <additionalJvmArgs>
                        -Dorg.apache.cxf.Logger=null
                    </additionalJvmArgs>
                    <encoding>UTF-8</encoding>
                    <sourceRoot>${project.build.directory}/generated-sources/java</sourceRoot>
                    <wsdlRoot>${project.basedir}/src/main/resources/wsdl</wsdlRoot>
                </configuration>
                <executions>
                    <execution>
                        <id>wsdl-lp-to-java</id>
                        <configuration>
                            <wsdlOptions>
                                <wsdlOption>
                                    <wsdl>${project.basedir}/src/main/resources/wsdl/lp/ExtCaseManagementService.wsdl</wsdl>
                                    <wsdlLocation>classpath:wsdl/lp/ExtCaseManagementService.wsdl</wsdlLocation>
                                </wsdlOption>
                            </wsdlOptions>
                        </configuration>
                        <goals>
                            <goal>wsdl2java</goal>
                        </goals>
                        <phase>validate</phase>
                    </execution>
                    <execution>
                        <id>wsdl-oms-to-java</id>
                        <configuration>
                            <wsdlOptions>
                                <wsdlOption>
                                    <wsdl>${project.basedir}/src/main/resources/wsdl/oms/RTTSAPI_v02.wsdl</wsdl>
                                    <wsdlLocation>classpath:wsdl/oms/RTTSAPI_v02.wsdl</wsdlLocation>
                                </wsdlOption>
                                <wsdlOption>
                                    <wsdl>${project.basedir}/src/main/resources/wsdl/oms/RTTSASYNCAPI_v01.wsdl</wsdl>
                                    <wsdlLocation>classpath:wsdl/oms/RTTSASYNCAPI_v01.wsdl</wsdlLocation>
                                </wsdlOption>
                            </wsdlOptions>
                        </configuration>
                        <goals>
                            <goal>wsdl2java</goal>
                        </goals>
                        <phase>validate</phase>
                    </execution>
                </executions>
            </plugin>
guai commented 2 years ago

Upd: It seems to work this way:

cxfCodegen {
    wsdl2java {
        register("lp") {
            wsdl.set(projectDir.resolve("src/main/resources/wsdl/lp/ExtCaseManagementService.wsdl"))
            wsdlLocation.set("classpath:wsdl/lp/ExtCaseManagementService.wsdl")
        }
        val sameDir = buildDir.resolve("generated-sources/cxf/oms")
        register("oms1") {
            wsdl.set(projectDir.resolve("src/main/resources/wsdl/oms/RTTSAPI_v02.wsdl"))
            wsdlLocation.set("classpath:wsdl/oms/RTTSAPI_v02.wsdl")
            outputDir.set(sameDir)
        }
        register("oms2") {
            wsdl.set(projectDir.resolve("src/main/resources/wsdl/oms/RTTSASYNCAPI_v01.wsdl"))
            wsdlLocation.set("classpath:wsdl/oms/RTTSASYNCAPI_v01.wsdl")
            outputDir.set(sameDir)
        }
    }
}
guai commented 2 years ago

Upd2: but it breaks gradle's caching mechanism

ciscoo commented 2 years ago

The extension is deprecated, create the tasks directly.

import io.mateo.cxf.codegen.wsdl2java.Wsdl2Java

plugins {
    java
    id("io.mateo.cxf-codegen") version "1.0.0"
}

repositories {
    mavenCentral()
}

tasks {
    register("lp", Wsdl2Java::class) {
        toolOptions {
            wsdl.set(file("src/main/resources/wsdl/lp/ExtCaseManagementService.wsdl"))
            wsdlLocation.set("classpath:wsdl/lp/ExtCaseManagementService.wsdl")
        }
    }
    register("oms1", Wsdl2Java::class) {
        toolOptions {
            wsdl.set(file("src/main/resources/wsdl/oms/RTTSAPI_v02.wsdl"))
            wsdlLocation.set("classpath:wsdl/oms/RTTSAPI_v02.wsdl")
        }
    }
    register("oms2", Wsdl2Java::class) {
        toolOptions {
            wsdl.set(file("src/main/resources/wsdl/oms/RTTSASYNCAPI_v01.wsdl"))
            wsdlLocation.set("classpath:wsdl/oms/RTTSASYNCAPI_v01.wsdl")
        }
    }
    withType(Wsdl2Java::class).configureEach {
        jvmArgs = listOf("-Dorg.apache.cxf.Logger=null")
        allJvmArgs = listOf("-Dfile.encoding=UTF-8")
        if (name == "oms1" || name == "oms2") {
            toolOptions {
                outputDir.set(layout.buildDirectory.dir("generated-sources/cxf/oms"))
            }
        }
    }
}
guai commented 2 years ago

When I generate java to separate folders there are class duplicates. When I set them both the same output dir, gradle's caches being disturbed and so the task is never up-to-date.

I managed to overcome the issue with gradle's cache by defining a new Copy task which combines the outputs in its own directory plus filtering out the original task's directories from the sourceSet.

But it kinda feels wrong. Could you pls extract the generation logic into its own class apart from adding them to sourceSets?

ciscoo commented 2 years ago

When I generate java to separate folders there are class duplicates

Your WSDLs contain the same definitions or objects defined in them.

When I set them both the same output dir, gradle's caches being disturbed and so the task is never up-to-date.

This is because when one task finishes generating its output, the next in line sees that the output has changed therefore causes it to be out of date. Each task has its own output directory to avoid this situation for that reason as discussed in https://github.com/ciscoo/cxf-codegen-gradle/discussions/16,

I managed to overcome the issue with gradle's cache by defining a new Copy task which combines the outputs in its own directory plus filtering out the original task's directories from the sourceSet.

That seems to be your only solution due to your WSDLs containing the same definitions.

Could you pls extract the generation logic into its own class apart from adding them to sourceSets?

This plugin does not have any generation logic. All of the actual generation is handled by the wsdl2java tool. The only thing this plugin generates is the command line arguments which are passed to the aforementioned tool.

However, an option can be added to determine whether or not the output should be added to the main source set. Would that help?

guai commented 2 years ago

"Would that help?" I think it should

guai commented 2 years ago

It seems that maven plugin didn't have this problems cause it doesn't give much about caching. It just dumps whatever there is into one dir overwriting files. But one might expect it to just work since it is stated that this plugin is a port of maven's one.

"WSDLs containing the same definitions." it does. but I have no desire to touch those wsdl files. I'm no author and really am not skilled in that kind of stuff

ciscoo commented 2 years ago

You can't really compare Maven's incremental build to Gradle's as they are different.

But one might expect it to just work since it is stated that this plugin is a port of maven's one.

Not necessarily. It is called out in the README that it is a port of the Maven plugin, but it is further explained in the docs (emphasis mine):

CXF Codegen is a Gradle plugin port of the Maven plugin. The Gradle plugin offers an API similar to the one offered by the Maven plugin. The API is not a 1:1 port and leans heavily on Gradle idioms and conventions.

guai commented 2 years ago

tip for those with the same problem: don't try to do what maven's plugin does, generate each wsdl to its own package and fix your imports - you'll save yourself a lot of trouble

ciscoo commented 2 years ago

Closing since there is nothing else here.

Raised https://github.com/ciscoo/cxf-codegen-gradle/issues/28 for configuration option.

Hc747 commented 2 years ago

tip for those with the same problem: don't try to do what maven's plugin does, generate each wsdl to its own package and fix your imports - you'll save yourself a lot of trouble

Can you share your solution re: the use of a copy task? Currently encountering the same issue! 👍

Hc747 commented 2 years ago

This is my approach thus far @guai; it fixes the duplication and caching issues!

afterEvaluate {
        // Generate SOAP bindings prior to compiling the Java Source Code for the project.
        final def compile = tasks.findByName('compileJava')
        final def wsdl = tasks.findByName('wsdl2java')

        if (compile && wsdl) {
            compile.dependsOn(wsdl)
        }

        // Register an aggregating task that combines the outputs of each task, omits duplicates,
        // and includes them within the main java source set.
        if (wsdl) {
            final def build = file("$projectDir/build/src/wsdl2java/java")
            final def collect = tasks.register('collect-wsdls', Copy) {
                group(CxfCodegenPlugin.WSDL2JAVA_GROUP)
                final def tasks = tasks.withType(Wsdl2Java)
                final def generated = tasks.collect { it.getOutputs() }

                from generated
                into build
            }
            wsdl.configure { finalizedBy collect }
            sourceSets.main.java.srcDirs += [build]
        }
    }
Hc747 commented 2 years ago

@ciscoo Do you have an idea of when the version of the plugin that allows for configuration of source set inclusion (via
Wsdl2Java#addToMainSourceSet) will be published as a non-snapshot release? Really appreciate this plugin, cheers!

guai commented 2 years ago

Hi, @Hc747 Here is my combining task

package wsdl2java

import org.gradle.api.file.DuplicatesStrategy
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.api.tasks.TaskProvider
import org.gradle.kotlin.dsl.getByType
import javax.inject.Inject

abstract class Combine @Inject constructor(vararg tasks: TaskProvider<*>) : Copy() {

    init {
        group = "wsdl2java"
        destinationDir = project.buildDir.resolve("$name-combined-generated-sources")
        duplicatesStrategy = DuplicatesStrategy.EXCLUDE
        from(tasks)
        project.extensions.getByType<SourceSetContainer>().named(SourceSet.MAIN_SOURCE_SET_NAME).configure {
            java {
                exclude { it.file in inputs.files }
                srcDir(destinationDir)
            }
        }
    }
}

you can place it into the buildSrc and then use like so:

tasks {
    val oms1 = register<Wsdl2Java>("oms1") {
        toolOptions {
            wsdl.set(projectDir.resolve("src/main/resources/wsdl/oms/RTTSAPI_v02.wsdl"))
            wsdlLocation.set("classpath:wsdl/oms/RTTSAPI_v02.wsdl")
        }
    }
    val oms2 = register<Wsdl2Java>("oms2") {
        toolOptions {
            wsdl.set(file("src/main/resources/wsdl/oms/RTTSASYNCAPI_v01.wsdl"))
            wsdlLocation.set("classpath:wsdl/oms/RTTSASYNCAPI_v01.wsdl")
        }
    }
    register<wsdl2java.Combine>("oms", arrayOf(oms2, oms1)).also {
        named("compileJava") { dependsOn(it) }
    }
}

It looks like your approach is quite similar. But I don't recommend it. In my case there were wsdl files in which were the same Entities defines, but of slightly different versions. When we were building with maven it was just dumping the files into the same dir and somehow by luck this worked. It's better to get proper wsdl without duplicates and of version matching current state of the web-service.

ciscoo commented 2 years ago

@Hc747 I can publish a new release later today after work. So, sometime after 5PM CST.

ciscoo commented 2 years ago

v1.0.1 released. Give it a try @Hc747

Hc747 commented 2 years ago

Hi, @Hc747 Here is my combining task

package wsdl2java

import org.gradle.api.file.DuplicatesStrategy
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.api.tasks.TaskProvider
import org.gradle.kotlin.dsl.getByType
import javax.inject.Inject

abstract class Combine @Inject constructor(vararg tasks: TaskProvider<*>) : Copy() {

    init {
        group = "wsdl2java"
        destinationDir = project.buildDir.resolve("$name-combined-generated-sources")
        duplicatesStrategy = DuplicatesStrategy.EXCLUDE
        from(tasks)
        project.extensions.getByType<SourceSetContainer>().named(SourceSet.MAIN_SOURCE_SET_NAME).configure {
            java {
                exclude { it.file in inputs.files }
                srcDir(destinationDir)
            }
        }
    }
}

you can place it into the buildSrc and then use like so:

tasks {
    val oms1 = register<Wsdl2Java>("oms1") {
        toolOptions {
            wsdl.set(projectDir.resolve("src/main/resources/wsdl/oms/RTTSAPI_v02.wsdl"))
            wsdlLocation.set("classpath:wsdl/oms/RTTSAPI_v02.wsdl")
        }
    }
    val oms2 = register<Wsdl2Java>("oms2") {
        toolOptions {
            wsdl.set(file("src/main/resources/wsdl/oms/RTTSASYNCAPI_v01.wsdl"))
            wsdlLocation.set("classpath:wsdl/oms/RTTSASYNCAPI_v01.wsdl")
        }
    }
    register<wsdl2java.Combine>("oms", arrayOf(oms2, oms1)).also {
        named("compileJava") { dependsOn(it) }
    }
}

It looks like your approach is quite similar. But I don't recommend it. In my case there were wsdl files in which were the same Entities defines, but of slightly different versions. When we were building with maven it was just dumping the files into the same dir and somehow by luck this worked. It's better to get proper wsdl without duplicates and of version matching current state of the web-service.

Thankfully for my use case, there were duplicates, but they were of entities with the same version - thank you for providing your solution and approach nonetheless!

v1.0.1 released. Give it a try @Hc747

You're fantastic - thank you very much.

Happy festivities to you both! :)