sorenpoulsen.com header

JAX-WS SOAP Web Service Client For Java 11 With Maven

In this post we are going to create a simple JAX-WS SOAP Web Service client using what used to be the JAX-WS reference implementation bundled with the JDK, but is now an external library managed by the Eclipse Foundation available from Maven Central.

The JAX-WS client Maven project discussed in this post is available from GitHub.

One does not simply migrate to Java 11 meme

Removing significant features from the JDK after decades of backwards compatibility is obviously very unpleasant for existing enterprise projects, but there is good reason to try and stay with the good old Metro implementation of JAX-WS, as it is known for its interoperability with other platforms and extensive support for WS-* extensions.

But first, what changed?

The JAX-WS and JAXB reference implementation developed as part of the Metro project and included in JDK 6 for convenience, was deprecated for removal in JDK 9 and finally removed in JDK 11.

Metro, along with JavaEE, was submitted to the Eclipse Foundation and is now known as Eclipse Metro.

The new JAX-WS and JAXB RI libraries are available from Maven Central with Java namespaces changed from javax.xml.* to jakarta.xml.*.

The wsimport, wsgen, xjc and schemagen tools that were bundled as part of the JDK and often used through the jaxws-maven-plugin developed by codehaus, are now used through a similar plugin that is part of the Eclipse Metro JAX-WS RI.

We are going to generate the JAX-WS client from a WSDL file using the new maven plugin.

Introducing the test service

The test service is of the Document Literal Wrapped type bound to a SOAP-over-HTTP implementation.

It has a SendMessage operation that sends a string and returns another string.

The test.wsdl file is as follows:

<?xml version="1.0"?>
<definitions name="TestService" 
  targetNamespace="http://tempuri.org/"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:tns="http://tempuri.org/"
  xmlns="http://schemas.xmlsoap.org/wsdl/">

  <types>
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
      targetNamespace="http://tempuri.org/">

      <xsd:element name="SendMessage">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="Message" type="xsd:string" />
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>

      <xsd:element name="SendMessageResponse">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="MessageResponse" type="xsd:string" />
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
    </xsd:schema>
  </types>

  <message name="TestRequestMessage">
    <part name="TestRequestPart" element="tns:SendMessage" />
  </message>
  <message name="TestResponseMessage">
    <part name="TestResponsePart" element="tns:SendMessageResponse" />
  </message>

  <portType name="TestPortType">
    <operation name="SendMessage">
      <input name="TestInput" message="tns:TestRequestMessage" />
      <output name="TestOutput" message="tns:TestResponseMessage" />
    </operation>
  </portType>

  <binding name="TestBinding" type="tns:TestPortType">
    <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
    <operation name="SendMessage">
      <input name="TestInput">
        <soap12:body use="literal" />
      </input>
      <output name="TestOutput">
        <soap12:body use="literal" />
      </output>
    </operation>
  </binding>

  <service name="TestService">
    <port name="TestPort" binding="tns:TestBinding">
      <soap12:address location="http://tempuri.org/testservice" />
    </port>
  </service>

</definitions>

Prerequisites

You will need a recent Maven 3 and JDK 11 on path.

The client artifacts are generated from a WSDL file using the plugin's wsimport goal.

There is no need to install any of the schema commandline tools as the plugin uses wsimport directly from its own jaxws-tools.jar dependency.

Add the JAX-WS API and implementation

So now that JAX-WS is are no longer part of Java's standard API, we have to add the API and the implementation explicitly as runtime dependencies in the Maven project's POM file when deploying to a web server such as Tomcat or when using JAX-WS in standalone applications.

If we are deploying to a full Jakarta EE server then we use <scope>provided</scope> to avoid bundling the libraries with the app.

<dependencies>
<dependency> <groupId>jakarta.xml.ws</groupId> <artifactId>jakarta.xml.ws-api</artifactId> <version>3.0.1</version> </dependency>
<dependency> <groupId>com.sun.xml.ws</groupId> <artifactId>jaxws-rt</artifactId> <version>3.0.2</version> <scope>runtime</scope> </dependency>
</dependencies>

Add the JAX-WS Maven plugin

The JAX-WS Maven plugin is added to the POM file and configured to execute the wsimport goal.

The test.wsdl file is read from the project's src/main/resources folder during artifacts generation and is read from the root of the classpath /test.wsdl at runtime.

The "extension" property tells the plugin to support soap v1.2 bindings.

<build>
  <plugins>

    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.9.0</version>
      <configuration>
        <release>11</release>
      </configuration>
    </plugin>

    <plugin>
      <groupId>com.sun.xml.ws</groupId>
      <artifactId>jaxws-maven-plugin</artifactId>
      <version>3.0.2</version>
      <executions>
        <execution>
          <goals>
            <goal>wsimport</goal>
          </goals>
        </execution>
      </executions>
      <configuration>
        <wsdlLocation>/test.wsdl</wsdlLocation>
        <wsdlDirectory>${project.basedir}/src/main/resources/</wsdlDirectory>
        <extension>true</extension>
      </configuration>
      <dependencies>
        <dependency>
          <groupId>com.sun.xml.ws</groupId>
          <artifactId>jaxws-tools</artifactId>
          <version>3.0.2</version>
        </dependency>
      </dependencies>
    </plugin>

  </plugins>
</build>

And finally we can run maven to generate the JAX-WS client artifacts.

$ mvn install

Using the client

Using the generated artifacts to invoke the service goes something like this.

  TestService testService = new TestService();
  TestPortType testPort = testService.getTestPort();
  BindingProvider binding = (BindingProvider) testPort;
  binding.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://localhost:8088/mockTestBinding");
  String response = testPort.sendMessage("hello");

This post doesn't cover how to use the wsgen goal to generate a service provider, but you could load the test.wsdl file in a SoapUI project and let it run a mock service for a quick test of the client.

{{model.usr.name}}
{{cmt.user.name}}
{{cmt.user.name}}
{{childcmt.user.name}}
{{childcmt.user.name}}