This guide walks you through the process of consuming a SOAP-based web service with Spring.
You will build a client that fetches country data from a remote, WSDL-based web service by using SOAP. You can find out more about the country service and run the service yourself by following this guide.
The service provides country data. You will be able to query data about a country based on its name.
Note
|
If you read Producing a SOAP web service, you
might wonder why this guide does not use spring-boot-starter-ws ? That Spring Boot
starter is only for server-side web services. That starter brings on board such things as
embedded Tomcat, which is not needed to make a web call.
|
Follow the steps in the
companion guide or clone the
repository and run the service
(for example, by using mvn spring-boot:run
) from its complete
directory. You can
verify that it works by visiting http://localhost:8080/ws/countries.wsdl
in your
browser. If you don’t do this you will see a confusing exception in your build later from the JAXB tooling.
For all Spring applications, you should start with the Spring Initializr. The Initializr offers a fast way to pull in all the dependencies you need for an application and does a lot of the setup for you. This example needs only the Spring Web Services dependency.
To initialize the project:
-
Navigate to https://start.spring.io. This service pulls in all the dependencies you need for an application and does most of the setup for you.
-
Choose either Gradle or Maven and the language you want to use. This guide assumes that you chose Java.
-
Click Dependencies and select Spring Web Services.
-
Click Generate.
-
Download the resulting ZIP file, which is an archive of a web application that is configured with your choices.
Note
|
If your IDE has the Spring Initializr integration, you can complete this process from your IDE. |
Note
|
You can also fork the project from Github and open it in your IDE or other editor. |
The build files created by the Spring Initializr need quite a bit of work for this guide.
Also, the modifications to pom.xml
(for Maven) and build.gradle
(for Gradle) differ
substantially.
For Maven, you need to add a dependency, a profile, and a WSDL generation plugin.
The following listing shows the dependency you need to add in Maven:
link:complete/pom.xml[role=include]
The following listing shows the profile you need to add in Maven if you want it to work with Java 11:
link:complete/pom.xml[role=include]
The Generate Domain Objects Based on a WSDL section describes the WSDL generation plugin.
The following listing shows the final pom.xml
file:
link:complete/pom.xml[role=include]
For Gradle, you need to add a dependency, a configuration, a bootJar
section, and a WSDL
generation plugin.
The following listing shows the dependency you need to add in Gradle:
link:complete/build.gradle[role=include]
Note the exclusion of Tomcat. If Tomcat is allowed to run in this build, you get a port collision with the Tomcat instance that provides the country data.
The following listing shows the bootJar
section you need to add in Gradle:
link:complete/build.gradle[role=include]
The Generate Domain Objects Based on a WSDL section describes the WSDL generation plugin.
The following listing shows the final build.gradle
file:
link:complete/build.gradle[role=include]
The interface to a SOAP web service is captured in
WSDL. JAXB provides a way
to generate Java classes from WSDL (or rather, the XSD contained in the <Types/>
section
of the WSDL). You can find the WSDL for the country service at
http://localhost:8080/ws/countries.wsdl
.
To generate Java classes from the WSDL in Maven, you need the following plugin setup:
link:complete/pom.xml[role=include]
This setup will generate classes for the WSDL found at the specified URL, putting those
classes in the com.example.consumingwebservice.wsdl
package. To generate that code run ./mvnw compile
and then look in target/generated-sources
if you want to check that it worked.
To do the same with Gradle, you will need the following in your build file:
link:complete/build.gradle[role=include]
As Gradle does not (yet) have a JAXB plugin, it involves an Ant task, which makes it a bit
more complex than in Maven. To generate that code run ./gradlew compileJava
and then look in build/generated-sources
if you want to check that it worked.
In both cases, the JAXB domain object generation process has been wired into the build tool’s lifecycle, so you need not run any extra steps once you have a successful build.
To create a web service client, you have to extend the
WebServiceGatewaySupport
class and code your operations, as the following example (from
src/main/java/com/example/consumingwebservice/CountryClient.java
) shows:
link:complete/src/main/java/com/example/consumingwebservice/CountryClient.java[role=include]
The client contains one method (getCountry
) that does the actual SOAP exchange.
In this method, both the GetCountryRequest
and the GetCountryResponse
classes are
derived from the WSDL and were generated in the JAXB generation process (described in
Generate Domain Objects Based on a WSDL). It creates the GetCountryRequest
request object and sets it up with the
country
parameter (the name of the country). After printing out the country name, it
uses the
WebServiceTemplate
supplied by the WebServiceGatewaySupport
base class to do the actual SOAP exchange. It
passes the GetCountryRequest
request object (as well as a SoapActionCallback
to pass
on a SOAPAction header with
the request) as the WSDL described that it needed this header in the <soap:operation/>
elements. It casts the response into a GetCountryResponse
object, which is then
returned.
Spring WS uses Spring Framework’s OXM module, which has the Jaxb2Marshaller
to serialize
and deserialize XML requests, as the following example (from
src/main/java/com/example/consumingwebservice/CountryConfiguration.java
) shows:
link:complete/src/main/java/com/example/consumingwebservice/CountryConfiguration.java[role=include]
The marshaller
is pointed at the collection of generated domain objects and will use
them to both serialize and deserialize between XML and POJOs.
The countryClient
is created and configured with the URI of the country service shown
earlier. It is also configured to use the JAXB marshaller.
This application is packaged up to run from the console and retrieve the data for a given
country name, as the following listing (from
src/main/java/com/example/consumingwebservice/ConsumingWebServiceApplication.java
)
shows:
link:complete/src/main/java/com/example/consumingwebservice/ConsumingWebServiceApplication.java[role=include]
The main()
method defers to the
SpringApplication
helper class, providing
CountryConfiguration.class
as an argument to its run()
method. This tells Spring to
read the annotation metadata from CountryConfiguration
and to manage it as a component
in the Spring application context.
Note
|
This application is hard-coded to look up 'Spain'. Later in this guide, you will see how to enter a different symbol without editing the code. |
Logging output is displayed. The service should be up and running within a few seconds.
The following listing shows the initial response:
Requesting country data for Spain
<getCountryRequest><name>Spain</name>...</getCountryRequest>
You can plug in a different country by running the following command:
java -jar build/libs/gs-consuming-web-service-0.1.0.jar Poland
Then the response changes to the following:
Requesting location for Poland
<getCountryRequest><name>Poland</name>...</getCountryRequest>
Congratulations! You have just developed a client to consume a SOAP-based web service with Spring.
The following guides may also be helpful: