Automate SOAP Client Auto-Generation Routines With WSDL Import for SBT and Scala

DZone 's Guide to

Automate SOAP Client Auto-Generation Routines With WSDL Import for SBT and Scala

See how to automate SOAP client auto-generation routines with WSDL import for SBT and Scala.

· Integration Zone ·
Free Resource

Image title

Automate SOAP client auto-generation routines.

Working with SOAP often gets tricky, and dealing with WSDL might be a huge contribution to the complexity of this task. Really, it could be the least expected thing to face when you are into a modern and fancy language like Scala, for example, which is well-known for its reactiveness and asynchronous way of dealing with requests.

In fact, many of the software developers that have made their way into the industry quite recently might not even know about SOAP and WSDL protocols, and get quickly annoyed or even enraged when first trying to connect to such a legacy service. So, should we deprecate this in favor of a modern technology stack or is there a less painful solution?

You may also like:  Understanding WSDL

SOAP: Legacy

It’s hard to argue that this SOAP thing sounds quite outdated nowadays, especially in contrast with the current state of technology. Writing a WSDL client from scratch with Kotlin, Scala, or another modern language could be a pain, and lack of proper documentation for it doesn’t make life easier. But I have good news for you; there is a spot of light in the dark SOAP kingdom.

Well, actually, WSDL is the one. Despite being heavyweight and somewhat ugly, it has a certain advantage. The excessiveness of the WSDL format makes it quite easy to generate the client (and also server) code (maybe not for humans, but definitely for automated systems).

Even compared to modern API specifications, it could actually stay on par with OpenAPI or fancy Swagger API concepts where everything is described in a language-agnostic spec. This enables huge opportunities for interoperability between different platforms and languages, down to the level of implementation. For example, if one exposes let’s say a .NET web service with WSDL spec, another could automatically generate a JVM-based client to connect to it with little to no pain of data formats conversion or incompatibility.

WSDL Import Magic

Let’s spin it further and talk about automated code generation. You might be surprised, but most enterprise-ish platforms, mainly Java and .NET, come with WSDL code-generating tools out of the box. For example, there is a wsimport that comes as a part of a JDK distribution. Such tools are quite powerful and should cover an auto-generation task end-to-end. The only remaining part is to connect your business logic to the client code and make use of it.

So, since we are on the Scala theme currently, let’s look deeper into Java’s wsimport tool:

wsimport -p stockquote http://stockquote.example.com/quote?wsdl

The command takes a WSDL schema as a required parameter, and basically it’s just enough to produce a whole set of POJOs and interfaces that are marked with all proper annotations. The latter ones actually do the trick: this is essentially what makes all things possible. When executed, JVM wires your client code together with internal web service client implementation, that comes out of the box, so you don’t need to bother much about low-level networking & IO. The rest of the business is to handle ins and outs properly and be careful with errors and exceptions.

Bring Automation to the Next Level With SBT

Alright, it’s time for some hands-on. Imagine we have some SOAP web services hosted at your.server.com that we need to connect to and they expose WSDL: let's say, to do any kind of orders management. Run the code generator when pointed to the orders web service:

wsimport -s ../src/main/java -extension -p your.package.wsdl.orders \
  -XadditionalHeaders -Xnocompile \

It produces a number of raw Java code in the output folder with all the packages prefixed as specified above: your.package.wsdl.orders. We could proceed with connecting our business logic as suggested previously. But wait for a second, what if the server-side changes? We will be aware of it only at the moment of actual code execution (or on the integration tests failure moment, if we have some). Not pretty. It quickly gets uglier if you will think of committing all this boilerplate Java bean code into your pristine Scala repository.

Of course, it would be way nicer to generate all that stuff automatically and keep things lean and clean. The first step for this would be to automate getting all WSDL classes with one command and make a Shell script out of this. I actually made one for you so you can have a look: wsdl_import.sh.

Then we could just wrap it with a build task: let’s take SBT as an example since we are on Scala, so something like this should work:

lazy val wsdlImport = TaskKey[Unit]("wsdlImport", "Generates Java classes from WSDL")

wsdlImport := {
  val wsdlSources = "./wsdl/src/main/java"
  val d = file(wsdlSources)
  if (d.isDirectory) {
    // don't forget to rename to your fav one in line with WSDL generating sh
    val gen = file(s"$wsdlSources/github/sainnr/wsdl")
    if (!gen.exists() || gen.listFiles().isEmpty) {
      import sys.process._

      println("[wsdl_import] Importing Java beans from WSDL...")
      "./wsdl/bin/wsdl_import.sh" !
    } else
      println("[wsdl_import] Looks like WSDL is already imported, skipping.")
  } else
    println(s"[wsdl_import] Make sure the directory ${d.absolutePath} exists.")

Raw code on GitHub

Now, we need to make sure we have all this code before the Scala part compiles for obvious reasons. Easy-peasy, we have SBT, so we just need to execute the Shell script as an SBT task like above and run things in the right order, correct? Well, it’s a bit more complicated in real life. Without getting into much of the details of how SBT works, things get much easier if we separate this WSDL-Java part into a self-containing sub-project, and make a proper dependency in the master SBT configuration.

lazy val wsdl = (project in file("wsdl"))
  .settings (
    sources in (Compile, doc) := Seq.empty

lazy val root = (project in file("."))

Raw code on GitHub

When you compile the master project, SBT first ensures the sub-project is already compiled. But there is a catch: when you have just checked out your repository, you may not have executed the compilation. So when you first open it in the editor, some of the dependencies will be missing, of course. Hopefully the only thing you need is to run an sbt compile command and, perhaps, refresh the project in IDE.

There might be another caveat if you are running your Scala application as a stand-alone client or in a lean web container (e.g. Netty if you are using Play Framework). In this case, it’s very likely the application runtime will be missing the implementation bit that helps JVM to do the SOAP magic for you, thanks to modern JRE versions and Java Jigsaw project. No need to panic though, just add a few libraries to your dependency list or throw a single rt.jar from your JRE distribution as an unmanaged dependency:

// ...
unmanagedJars in Test += Attributed.blank(
  file(System.getenv("JAVA_HOME") + "/jre/lib")
// ...


Alright, as a recap: we have learned a bit about SOAP and WSDL and hopefully realized it’s not such a nightmare to work with, thanks to all these code generators and excessive WSDL specs. We also figured out how to automate a dirty job and found a way to keep our repositories pristine and clean from unwanted boilerplate code.

It took some knowledge of SBT to configure compilation order and dependencies properly, but after all, it should work quite smoothly. To simplify things further, I made a small bootstrap template that should help you kick-start a project next time: https://github.com/sainnr/sbt-scala-wsdl-template.

I hope you enjoyed this little back-to-the-past journey!

Further Reading

Creating a SOAP Web Service With Spring Boot Starter Web Services

Top 19 SOAP Interview Questions

integration ,sbt ,scala ,soap ,tutorial ,web service ,web service clients ,wsdl

Published at DZone with permission of Vladimir Salin . See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}