The spring-boot-starter-web-services dependency includes the needed dependencies for using Spring Web Services.
The spring-boot-starter-test includes the dependencies for testing Spring Boot applications with libraries that include JUnit, Hamcrest and Mockito.
In the plugins section, you’ll find the Spring Boot Maven Plugin. spring-boot-maven-plugin allows us to build a single, runnable “uber-jar”. This is a convenient way to execute and transport code.
Also, the plugin allows you to start the example via a Maven command.
We want to be able to directly use the person and greeting elements (defined in the types section of the above Hello World WSDL) in our Java code. To achieve this we will use JAXB to generate the corresponding Java classes.
The plugin looks into the defined <schemaDirectory> in order to find any WSDL files for which it needs to generate the Java classes.
Make sure that the helloworld.wsdl file is available under /src/main/resources.
Execute the following Maven command to trigger the code generation:
This results in a number of generated Java classes under /target/generated-sources/xjc. You should find Person and Greeting. We will use these classes when we implement the client and provider of the SOAP service.
4. Spring Boot Setup
Spring Boot is used in order to make a Spring WS example application that you can “just run”.
We start by creating a SpringWsApplication which contains the main() method that uses Spring Boot’s SpringApplication.run() method to launch the application.
The @SpringBootApplication annotation is a convenience annotation that adds: @Configuration, @EnableAutoConfiguration and @ComponentScan.
Spring Web Services supports multiple transport protocols. The most common is the HTTP transport, for which a custom MessageDispatcherServlet servlet is supplied. This is a standard Servlet which extends from the standard Spring Web DispatcherServlet (=central dispatcher for HTTP request handlers/controllers), and wraps a MessageDispatcher.
In other words: the MessageDispatcherServlet combines the attributes of the MessageDispatcher and DispatcherServlet and as a result allows the handling of XML messages over HTTP.
In the below WebServiceConfig configuration class we use a ServletRegistrationBean to register the MessageDispatcherServlet.
Note that it is important to inject and set the ApplicationContext to the MessageDispatcherServlet, otherwise it will not automatically detect other Spring Web Services related beans (such as the lower Wsdl11Definition).
The servlet mapping URI pattern on the ServletRegistrationBean is set to “/codenotfound/ws/*”. The web container will use this path to map incoming HTTP requests to the servlet.
The DefaultWsdl11Definition exposes a standard WSDL 1.1 using the specified Hello World WSDL file. The URL location at which this WSDL is available is determined by it’s Bean name in combination with the URI mapping of the MessageDispatcherServlet.
For the example below this is: [host]=”http://localhost:8080”+[servlet mapping uri]=”/codenotfound/ws/”+[WsdlDefinition bean name]=”helloworld”+[WSDL postfix]=”.wsdl”.
To enable the support for the @Endpoint annotation that we will use in the next section we need to annotate our configuration class with @EnableWs.
Now that our MessageDispatcherServlet is defined it will try to match incoming XML messages on the defined URI with one of the available handling methods. So all we need to do is set up an Endpoint that contains a handling method that matches the incoming request. This service endpoint can be a simple POJO with a number of Spring WS annotations as shown below.
The HelloWorldEndpoint POJO is annotated with the @Endpoint annotation which registers the class with Spring WS as a potential candidate for processing incoming SOAP messages. It contains a sayHello() method that receives a Person and returns a Greeting. Note that these are the Java classes that we generated earlier using JAXB (both are annotated with @XmlRoolElement).
To indicate what sort of messages a method can handle, it is annotated with the @PayloadRoot annotation that specifies a qualified name that is defined by a namespace and a local name (=localPart). Whenever a message comes in which has this qualified name for the payload root element, the method will be invoked.
The @ResponsePayload annotation makes Spring WS map the returned value to the response payload which in our example is the JAXB Greeting object.
The @RequestPayload annotation on the sayHello() method parameter indicates that the incoming message will be mapped to the method’s request parameter. In our case, this is the JAXB Person object.
The implementation of the sayHello service simply logs the name of the received Person and then uses this name to construct a Greeting that is also logged and then returned.
6. Creating the Client (Consumer)
Create a ClientConfig class and annotate it with @Configuration. This indicates that the class can be used by the Spring IoC container as a source of bean definitions.
The WebServiceTemplate is the core class for client-side Web service access in Spring-WS. It contains methods for sending requests and receiving response messages. Additionally, it can marshal objects to XML before sending them across a transport, and unmarshal any response XML into an object again.
As we will use JAXB to marshal our Person to a request XML and in turn unmarshal the response XML to our Greeting we need an instance of Spring’s Jaxb2Marshaller. This class requires a context path to operate, which you can set using the contextPath property. The context path is a list of colon (:) separated Java package names that contain schema derived classes.
In our example this is the package name of the generated Person and Greeting classes which is: com.codenotfound.types.helloworld.
The below ClientConfig configuration class specifies the WebServiceTemplate bean that uses the above Jaxb2Marshaller for marshaling and unmarshalling. We also set the default service URI to the service endpoint.
Note that the helloworld at the end of the default-uri can actually be omitted as previously we had specified “/codenotfound/ws/*” as URI of our endpoint servlet.
The client code is specified in the HelloWorldClient class. The sayHello() method creates a Person object based on the firstname and lastname input parameters.
The auto-wired WebServiceTemplate is used to marshal and send a person XML request towards the Hello World service. The result is unmarshalled to a Greeting object which is logged.
The @Component annotation will cause Spring to automatically import this bean into the container if automatic component scanning is enabled (adding the @SpringBootApplication annotation to the main SpringWsApplication class is equivalent to using @ComponentScan).
7. Testing the Web Service
Let’s create a basic unit test case in which the above client is used to send a request to the Hello World web service endpoint. We then verify if the response is equal to the expected greeting.