ciscoo / cxf-codegen-gradle

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

Support WSDL input from online WSDL URL #63

Closed a-glapinski closed 1 year ago

a-glapinski commented 1 year ago

As of right now, wsdl property in Wsdl2JavaOptions requires to specify a file in the local filesystem. As far as I understand, there is no way to specify external WSDL URL from which the code will be generated, because if wsdl property is not set, the whole task is skipped. It would be nice if there was an option to generate code using WSDLs from external URLs.

ciscoo commented 1 year ago

Correct, the tool options expects a file on your local machine.

I don't think this plugin should have functionality to retrieve a remote WSDL given that this can be accomplished either in Gradle directly (ex: URL.openConnection) or using an additional plugin such as de.undercouch.download to download the WSDL from a given URL.

Would an example in the documentation suffice?

a-glapinski commented 1 year ago

Thanks for the quick reply.

I would say that an example in the documentation using Gradle directly or an additional plugin would totally suffice, but I'm not sure that this method covers cases where in the source WSDL file there are <wsdl:import> directives which refer to another (relative) URLs.

Let's say that I wanted to download WSDL file from https://ewus.nfz.gov.pl/ws-broker-server-ewus-auth-test/services/Auth?wsdl. This WSDL imports another files, which I could also download, but that would only be a part of the problem. When I looked up one of the import directives, for example:

<wsdl:import namespace="http://wsdl.kamsoft.pl/common" location="Auth?wsdl=ws_common.wsdl"> </wsdl:import>

the location attribute points to another URL, relative to the current one. If I wanted to use the WSDL locally after downloading it, I think that I would have to change the location attribute values manually to point to the local files, which would defeat the purpose of automating the whole process.

I think that wsdl2java tool supports downloading from online URLs. Using the https://github.com/yupzip/wsdl2java plugin and the following config:

wsdl2java {
    wsdlDir = file("$projectDir/src/main/resources/wsdl/")
    stabilizeAndMergeObjectFactory = true
    includeJava8XmlDependencies = false
    cxfVersion = "4.0.0"
    cxfPluginVersion = "4.0.0"
    wsdlsToGenerate = listOf(
        listOf(
            "-xjc",
            "-xjc-Xnamespace-prefix",
            "-wsdlLocation", "https://ewus.nfz.gov.pl/ws-broker-server-ewus-auth-test/services/Auth?wsdl",
            "-autoNameResolution",
            "https://ewus.nfz.gov.pl/ws-broker-server-ewus-auth-test/services/Auth?wsdl",
        )
}

I was able to generate all Java classes from the WSDL file, including all classes from imports in the source WSDL file.

On the other hand, I'm not sure if lifting the requirement for providing File for wsdl property in Wsdl2JavaOptions would break things or not or if it's even desirable from your perspective to change it.

ciscoo commented 1 year ago

After some investigation, the wsdl2java tool itself retrieves WSDLs given a URL (and probably others such as XSDs). Minimal example without using the Wsdl2Java task:

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

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(17))
    }
}

repositories {
    mavenCentral()
}

dependencies {
    cxfCodegen(platform("org.apache.cxf:cxf-bom:4.0.0"))
    cxfCodegen("jakarta.xml.ws:jakarta.xml.ws-api:4.0.0")
    cxfCodegen("jakarta.annotation:jakarta.annotation-api:2.1.1")
}

tasks.register("example", JavaExec::class) {
    mainClass.set("org.apache.cxf.tools.wsdlto.WSDLToJava")
    classpath = configurations.cxfCodegen.get()
    args = listOf(
            "-d",
            layout.buildDirectory.dir("example-wsdl2java").get().asFile.absolutePath,
            "-autoNameResolution",
            "-wsdlLocation",
            "https://ewus.nfz.gov.pl/ws-broker-server-ewus-auth-test/services/Auth?wsdl",
            "https://ewus.nfz.gov.pl/ws-broker-server-ewus-auth-test/services/Auth?wsdl",
    )
}

This is definitely an oversight by me since I wrongly assumed that wsdl2java only supported local files. This is largely due to the fact that I have only (as far as I can recall) encountered usages of wsdl2java being used with local WSDLs.

On the other hand, I'm not sure if lifting the requirement for providing File for wsdl property in Wsdl2JavaOptions would break things or not or if it's even desirable from your perspective to change it.

Yes, changing wsdl from RegularFileProperty to Property<String> would definitely be a breaking change for the public API which is Wsdl2JavaOptions. So, as a stop gap:

  1. Add a new property Property<String> wsdlUrl which can either be an path of a local WSDL or a URL to a remote WSDL; the internal workings of wsdl2java takes care of figuring out which.
  2. Mark RegularFileProperty wsdl as optional since either this or wsdlUrl can be set, but not both.
  3. Add an onlyIf predicate to skip the task if neither properties are set; currently the wsdl property is annotated with @SkipWhenEmpty which takes care of that automatically, but with two properties it will need to be done manually for now.
  4. In 2.0.0 (Q3 or Q4 of 2023), make the breaking change from changing from RegularFileProperty to Property<String> and revert all of the above.
ciscoo commented 1 year ago

This change for (4) above is now available in 2.0.0-rc.1