WSDL client generation with Kotlin and Gradle

WSDL client generation with Kotlin and Gradle

How to use JAXWS to generate HTTP client code using the Gradle Kotlin DSL.

WSDL

WSDL (Web Services Description Language) is an XML format. It describes network services, their endpoints and the corresponding request and response formats.

WSDL is commonly used in conjunction with a SOAP (Simple Object Access Protocol) API. Soap can be thought of as a way of structuring your API. Similar to what REST (REpresentational State Transfer) is.

WSDL File

Typically, the result of using WSDL is a .wsdl file. You may have multiple files, one for each service, and these can come in handy when trying to consume an API.

Since a .wsdl file describes exactly what the API looks like, you can use it to generate HTTP client code. This means less code you have to write yourself. It also means reduced maintenance costs when an API gets updated.

Gradle Kotlin DSL

So how do you generate the HTTP client code? The first step is to create a configuration:

val jaxws by configurations.creating

Then we add a dependency to that configuration:

jaxws("com.sun.xml.ws:jaxws-tools:2.1.4")

JAXWS is a library which provides tooling, including the ability to read a .wsdl file.

Next we need to create a task to import our .wsdl file and produce our HTTP client code:

There are a few things to take note of here. We are using Ant to help create our task. The resulting task (named wsimport-myservice) will look for the file src/main/resources/META-INF/wsdl/SomeService.wsdl and generate HTTP client code. That code will live in src/main/java with a package of com.example.myproject.

The location of the .wsdl file is important. It needs to be compiled into your output, i.e. jar file. It needs to be accessed at runtime. Once you deploy your application it is common for hardcoded paths not to work correctly. To solve this we use the JAXWS catalog feature.

src/main/resources/META-INF/jax-ws-catalog.xml

<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system">
 <system systemId="http://localhost/wsdl/SomeService.wsdl"
 uri="wsdl/SomeService.wsdl"/>
</catalog>

Here we are telling JAXWS that it should map a wsdlLocation (defined in the gradle task) of http://localhost/wsdl/SomeService.wsdl to a URI of wsdl/SomeService.wsdl. Don't worry, your .wsdl file doesn't need to be available at http://localhost/wsdl/SomeService.wsdl. The catalog will always map this to the provided URI.

Thus, at runtime, the HTTP client code will know where to access the .wsdl file correctly.

HTTP Client

So we now have our HTTP client code, what next? To call a method against the API you need to get hold of a service. The name of this is defined in the .wsdl file. It should be listed within a wsdl:service tag. It will be something like SomeServiceEndpointImplService. This class will extend from javax.xml.ws.Service.

Autocomplete within an IDE can be very helpful at this stage.

val service = SomeServiceEndpointImplService()

Now you need to get the port. Under the same wsdl:service tag you will find a wsdl:port tag. Here you will find the name of your port.

val port = service.somePort

On the port, you will find a function corresponding to each of the functions on the API. It will detail what objects need to be passed in and what the return will be. Since these functions are API calls they can throw exceptions, so you should bear this in mind.

Kotlin Java Interop

JAXWS imports the .wsdl file into Java HTTP client code. This means that you will be calling Java from your Kotlin code.

Calling the API functions will feel a little strange, to begin with, if you're not used to Java interop. But it does become familiar over time.

Here is an example:

val service = SomeServiceEndpointImplService()
val port = service.somePort
val request = SomeRequestType().apply {
 someParam = SomeOtherModel().apply {
 thing = "thing"
 } 
 someOtherParam = "Something"
}
val response = port.someFunction(request)

Check out the Kotlin interop guide for more details on this.


Looking for something else?

Search over 400 blog posts from our team

Want to hear more?

Subscribe to our monthly digest of blogs to stay in the loop and come with us on our journey to make things better!