Skip to content

Commit

Permalink
Merge pull request #7 from bjornvester/next
Browse files Browse the repository at this point in the history
Version 1.1
  • Loading branch information
nc-bmv authored May 17, 2021
2 parents 765b128 + ad67353 commit e1ba046
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 12 deletions.
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Apply the plugin ID "com.github.bjornvester.wsdl2java" as specific in the [Gradl

```kotlin
plugins {
id("com.github.bjornvester.wsdl2java") version "1.0"
id("com.github.bjornvester.wsdl2java") version "1.1"
}
```

Expand Down Expand Up @@ -182,6 +182,23 @@ wsdl2java {
}
```

### Activating (third party) XJC plugins
To use third party plugins for the underlying XJC tool, supply the relevant dependencies to the `xjcPlugins` configuration.
Then set the plugin options through the `options` property.

For example, to use the "Equals" and "Hashcode" plugin from the [JAXB2 Basics](https://github.com/highsource/jaxb2-basics) project, configure the following:

```kotlin
dependencies {
implementation("org.jvnet.jaxb2_commons:jaxb2-basics-runtime:1.11.1")
xjcPlugins("org.jvnet.jaxb2_commons:jaxb2-basics:1.11.1")
}

wsdl2java {
options.addAll("-xjc-Xequals", "-xjc-XhashCode")
}
```

## Other
The plugin will add the following two dependencies to your `implementation` configuration:

Expand All @@ -200,5 +217,5 @@ If you need to compile additional XML schemas (xsd files) not directly reference
## Limitations
The CXF tool will overwrite generated classes from multiple WSDL files if they have the same qualified name.
Especially the `ObjectFactory` might be overwritten, which is annoying.
There is a similar plugin [here](https://github.com/nilsmagnus/wsdl2java) that merges them together, but it is deprecated.
There is a similar plugin [here](https://github.com/nilsmagnus/wsdl2java) that can merge them together, but it is deprecated.
I hope to port that functionality into this plugin at some point.
6 changes: 3 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {
}

group = "com.github.bjornvester"
version = "1.0"
version = "1.1"

repositories {
mavenCentral()
Expand Down Expand Up @@ -63,8 +63,8 @@ pluginBundle {
"wsdl2JavaPlugin" {
displayName = "Gradle Wsdl2Java plugin"
description = "Changes:\n" +
" - New configuration options added, including the ability to specify a binding file\n" +
" - Minimum version is now 6.0 (previously 5.4) due to internal use of new APIs"
" - Make it easier to use XJC plugins\n" +
" - Suppress a ton of harmless warnings from XJC"
tags = listOf("wsdl2java", "cxf", "wsimport")
}
}
Expand Down
3 changes: 2 additions & 1 deletion integration-test/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ include(
"bindings-datetime-test",
"filter-test",
"generated-annotation-test",
"utf8-test"
"utf8-test",
"xjc-plugins-test"
)
13 changes: 13 additions & 0 deletions integration-test/xjc-plugins-test/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
plugins {
id("com.github.bjornvester.wsdl2java")
id("com.github.bjornvester.wsdl2java.internal.java-conventions")
}

dependencies {
implementation("org.jvnet.jaxb2_commons:jaxb2-basics-runtime:1.11.1")
xjcPlugins("org.jvnet.jaxb2_commons:jaxb2-basics:1.11.1")
}

wsdl2java {
options.addAll("-xjc-Xequals", "-xjc-XhashCode")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?xml version='1.0' encoding='UTF-8'?><!-- 5 -->
<wsdl:definitions name="HelloWorldService"
targetNamespace="http://github.com/bjornvester/example/xjcplugins"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://github.com/bjornvester/example/xjcplugins"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<xs:schema targetNamespace="http://github.com/bjornvester/example/xjcplugins"
xmlns="http://github.com/bjornvester/example/xjcplugins"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="sayHi">
<xs:sequence>
<xs:element name="arg0" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="sayHiResponse">
<xs:sequence>
<xs:element name="return" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:element name="sayHi" nillable="true" type="sayHi"/>
<xs:element name="sayHiResponse" nillable="true" type="sayHiResponse"/>
</xs:schema>
</wsdl:types>
<wsdl:message name="sayHi">
<wsdl:part element="tns:sayHi" name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:message name="sayHiResponse">
<wsdl:part element="tns:sayHiResponse" name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:portType name="HelloWorld">
<wsdl:operation name="sayHi">
<wsdl:input message="tns:sayHi" name="sayHi">
</wsdl:input>
<wsdl:output message="tns:sayHiResponse" name="sayHiResponse">
</wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="HelloWorldServiceSoapBinding" type="tns:HelloWorld">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="sayHi">
<soap:operation soapAction="" style="document"/>
<wsdl:input name="sayHi">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="sayHiResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="HelloWorldService">
<wsdl:port name="HelloWorldPort" binding="tns:HelloWorldServiceSoapBinding">
<soap:address location="http://localhost:8080/MyCXFWebService/services/HelloWorldPort"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.github.bjornvester.wsdl2java;

import com.github.bjornvester.example.xjcplugins.HelloWorld;
import com.github.bjornvester.example.xjcplugins.SayHi;
import com.github.bjornvester.example.xjcplugins.SayHiResponse;

public class HelloWorldImpl implements HelloWorld {
@Override
public SayHiResponse sayHi(SayHi request) {
SayHiResponse response = new SayHiResponse();
response.setReturn("Hi, " + request.getArg0());
return response;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.github.bjornvester.wsdl2java;

import com.github.bjornvester.example.xjcplugins.HelloWorld;
import com.github.bjornvester.example.xjcplugins.SayHi;
import com.github.bjornvester.example.xjcplugins.SayHiResponse;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.jvnet.jaxb2_commons.lang.Equals2;
import org.jvnet.jaxb2_commons.lang.HashCode2;

import javax.xml.ws.Endpoint;

import static org.junit.jupiter.api.Assertions.assertTrue;

class HelloWorldTest {
String serviceAddress = "http://localhost:8899/HellowWorldService";
Endpoint endpoint;

@AfterEach
void stopEndpoint() {
if (endpoint != null) {
endpoint.stop();
}
}

@Test
void testServerClient() {
// Create server
endpoint = Endpoint.publish(serviceAddress, new HelloWorldImpl());

// Create client
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(HelloWorld.class);
factory.setAddress(serviceAddress);
HelloWorld client = (HelloWorld) factory.create();

// Call the service
SayHi sayHi = new SayHi();
sayHi.setArg0("Joe");
SayHiResponse response = client.sayHi(sayHi);
assertTrue(response.getReturn().contains("Hi"));

// Check the plugins
assertTrue(sayHi instanceof Equals2);
assertTrue(sayHi instanceof HashCode2);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.github.bjornvester.wsdl2java

import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME
import org.gradle.api.tasks.SourceSetContainer
Expand All @@ -14,14 +15,16 @@ class Wsdl2JavaPlugin : Plugin<Project> {
const val WSDL2JAVA_TASK_NAME = "wsdl2java"
const val WSDL2JAVA_EXTENSION_NAME = "wsdl2java"
const val WSDL2JAVA_CONFIGURATION_NAME = "wsdl2java"
const val XJC_PLUGINS_CONFIGURATION_NAME = "xjcPlugins"
}

override fun apply(project: Project) {
project.logger.info("Applying $PLUGIN_ID to project ${project.name}")
verifyGradleVersion()
project.plugins.apply(JavaPlugin::class.java)
val extension = project.extensions.create(WSDL2JAVA_EXTENSION_NAME, Wsdl2JavaPluginExtension::class.java)
val wsdl2JavaConfiguration = project.configurations.maybeCreate(WSDL2JAVA_CONFIGURATION_NAME)
val wsdl2JavaConfiguration = createResolvableConfiguration(project, WSDL2JAVA_CONFIGURATION_NAME)
createResolvableConfiguration(project, XJC_PLUGINS_CONFIGURATION_NAME)

wsdl2JavaConfiguration.defaultDependencies {
addLater(extension.cxfVersion.map { project.dependencies.create("org.apache.cxf:cxf-tools-wsdlto-frontend-jaxws:$it") })
Expand Down Expand Up @@ -57,4 +60,12 @@ class Wsdl2JavaPlugin : Plugin<Project> {
)
}
}

private fun createResolvableConfiguration(project: Project, name: String): Configuration {
return project.configurations.maybeCreate(name).apply {
isCanBeConsumed = false
isCanBeResolved = true
isVisible = false
}
}
}
44 changes: 41 additions & 3 deletions src/main/kotlin/com/github/bjornvester/wsdl2java/Wsdl2JavaTask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ package com.github.bjornvester.wsdl2java

import com.github.bjornvester.wsdl2java.Wsdl2JavaPlugin.Companion.WSDL2JAVA_CONFIGURATION_NAME
import com.github.bjornvester.wsdl2java.Wsdl2JavaPlugin.Companion.WSDL2JAVA_EXTENSION_NAME
import com.github.bjornvester.wsdl2java.Wsdl2JavaPlugin.Companion.XJC_PLUGINS_CONFIGURATION_NAME
import com.github.bjornvester.wsdl2java.Wsdl2JavaPluginExtension.Companion.MARK_GENERATED_NO
import com.github.bjornvester.wsdl2java.Wsdl2JavaPluginExtension.Companion.MARK_GENERATED_YES_JDK8
import com.github.bjornvester.wsdl2java.Wsdl2JavaPluginExtension.Companion.MARK_GENERATED_YES_JDK9
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.NamedDomainObjectProvider
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.internal.file.FileOperations
import org.gradle.api.model.ObjectFactory
Expand Down Expand Up @@ -49,6 +53,9 @@ open class Wsdl2JavaTask @Inject constructor(
@get:Classpath
val wsdl2JavaConfiguration = project.configurations.named(WSDL2JAVA_CONFIGURATION_NAME)

@get:Classpath
val xjcPluginsConfiguration: NamedDomainObjectProvider<Configuration> = project.configurations.named(XJC_PLUGINS_CONFIGURATION_NAME)

@get:OutputDirectory
val sourcesOutputDir: DirectoryProperty = objects.directoryProperty().convention(getWsdl2JavaExtension().generatedSourceDir)

Expand All @@ -64,8 +71,33 @@ open class Wsdl2JavaTask @Inject constructor(
fileOperations.delete(sourcesOutputDir)
fileOperations.mkdir(sourcesOutputDir)

val workerExecutor = workerExecutor.classLoaderIsolation {
classpath.from(wsdl2JavaConfiguration)
val workerExecutor = workerExecutor.processIsolation {
/*
All gradle worker processes have Xerces2 on the classpath.
This version of Xerces does not support checking for external file access (even if not used).
This causes it to log a whole bunch of stack traces on the form:
-- Property "http://javax.xml.XMLConstants/property/accessExternalSchema" is not supported by used JAXP implementation.
To avoid this, we fork the worker API to a separate process where we can set system properties to select which implementation of a SAXParser to use.
The JDK comes with an internal implementation of a SAXParser, also based on Xerces, but supports the properties to control external file access.
*/
forkOptions.systemProperties = mapOf(
"javax.xml.parsers.DocumentBuilderFactory" to "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl",
"javax.xml.parsers.SAXParserFactory" to "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl",
"javax.xml.validation.SchemaFactory:http://www.w3.org/2001/XMLSchema" to "org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory",
"javax.xml.accessExternalSchema" to "all"
)

if (logger.isDebugEnabled) {
// This adds debugging information on the XJC method used to find and load services (plugins)
forkOptions.systemProperties["com.sun.tools.xjc.Options.findServices"] = ""
}

// Set encoding (work-around for https://github.com/gradle/gradle/issues/13843)
forkOptions.environment("LANG", System.getenv("LANG") ?: "C.UTF-8")

classpath
.from(wsdl2JavaConfiguration)
.from(xjcPluginsConfiguration)
}

val defaultArgs = buildDefaultArguments()
Expand Down Expand Up @@ -107,6 +139,7 @@ open class Wsdl2JavaTask @Inject constructor(

private fun buildDefaultArguments(): MutableList<String> {
val defaultArgs = mutableListOf(
"-xjc-disableXmlSecurity",
"-autoNameResolution",
"-d",
sourcesOutputDir.get().toString()
Expand Down Expand Up @@ -140,6 +173,11 @@ open class Wsdl2JavaTask @Inject constructor(
}

private fun validateOptions() {
val supportedMarkGeneratedValues = listOf(MARK_GENERATED_NO, MARK_GENERATED_YES_JDK8, MARK_GENERATED_YES_JDK9)
if (markGenerated.get() !in supportedMarkGeneratedValues) {
throw GradleException("The property 'markGenerated' had an invalid value '${markGenerated.get()}'. Supported values are: $supportedMarkGeneratedValues")
}

if (options.isPresent) {
val prohibitedOptions = mapOf(
"-verbose" to "Configured through the 'verbose' property",
Expand All @@ -152,7 +190,7 @@ open class Wsdl2JavaTask @Inject constructor(

options.get().forEach { option ->
if (prohibitedOptions.containsKey(option)) {
throw GradleException("the option '$option' is not allowed in this plugin. Reason: ${prohibitedOptions[option]}")
throw GradleException("The option '$option' is not allowed in this plugin. Reason: ${prohibitedOptions[option]}")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ abstract class Wsdl2JavaWorker : WorkAction<Wsdl2JavaWorkerParams> {
WSDLToJava(args.toTypedArray()).run(ToolContext())
} catch (e: Exception) {
// We can't propagate the exception as it might contain classes from CXF which are not available outside the worker execution context
// Also, for some reason, we can't even put the message from the original exception in as it has shown to cause problems with serialization (though it is just a string)
logger.error("Failed to generate sources from WSDL", e)
// Also, for some reason, we can't even log the error as it sometimes fails with:
// java.io.StreamCorruptedException: invalid type code: 0C
// Seems like a bug in Gradle, possible with the error message contain multiple lines
// Until we have found the cause of it, we print directly to System.out
logger.error("Failed to generate sources from WSDL:")
e.printStackTrace()
throw GradleException("Failed to generate Java sources from WSDL. See the log for details.")
}
}
Expand Down

0 comments on commit e1ba046

Please sign in to comment.