[go: up one dir, main page]

0% found this document useful (0 votes)
103 views11 pages

Spring-WS Dev Guide

This document discusses various tools in Spring Web Services for validating XML payloads, transforming payloads between formats, and handling exceptions from web service endpoints. It describes the PayloadValidatingInterceptor for validating requests and responses against XML schemas, the PayloadTransformingInterceptor for transforming payloads between formats using XSLT, and several EndpointExceptionResolvers for mapping exceptions to SOAP faults. It also discusses how to write integration tests to test web service endpoints by sending sample requests and validating the responses.

Uploaded by

Neemias Júnior
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
103 views11 pages

Spring-WS Dev Guide

This document discusses various tools in Spring Web Services for validating XML payloads, transforming payloads between formats, and handling exceptions from web service endpoints. It describes the PayloadValidatingInterceptor for validating requests and responses against XML schemas, the PayloadTransformingInterceptor for transforming payloads between formats using XSLT, and several EndpointExceptionResolvers for mapping exceptions to SOAP faults. It also discusses how to write integration tests to test web service endpoints by sending sample requests and validating the responses.

Uploaded by

Neemias Júnior
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 11

09/03/2022 08:45 Spring Web Services Reference Documentation

One of the benefits of using a contract-first development style is that we can use the schema to
validate incoming and outgoing
XML messages. Spring-WS facilitates this with the
PayloadValidatingInterceptor . This interceptor requires a reference to
one
or more W3C XML or RELAX NG schemas, and can be set to validate requests or responses, or both.

Note that request validation may sound like a good idea, but makes the resulting Web service
very strict. Usually, it
is not really important whether the request validates, only if the
endpoint can get sufficient information to fullfill a
request. Validating the response
is a good idea, because the endpoint should adhere to its schema.
Remember
Postel's Law:
“Be conservative in what you do; be liberal in what you accept from others.”

Here is an example that uses the PayloadValidatingInterceptor ; in this


example, we use the schema in
/WEB-INF/orders.xsd to validate the response, but
not the request. Note that the PayloadValidatingInterceptor can
also accept
multiple schemas using the schemas property.

<bean id="validatingInterceptor"

class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">

<property name="schema" value="/WEB-INF/orders.xsd"/>

<property name="validateRequest" value="false"/>

<property name="validateResponse" value="true"/>

</bean>

Of course, you could use the WsConfigurerAdapter approach, as described above,


for the
PayloadValidatingInterceptor as well.

PayloadTransformingInterceptor

To transform the payload to another XML format, Spring Web Services offers the
PayloadTransformingInterceptor . This
endpoint interceptor is based on XSLT
style sheets, and is especially useful when supporting multiple versions of a Web service:
you can transform the older message format to the newer format. Here is an example to use the
PayloadTransformingInterceptor :

<bean id="transformingInterceptor"

class="org.springframework.ws.server.endpoint.interceptor.PayloadTransformingInterceptor">

<property name="requestXslt" value="/WEB-INF/oldRequests.xslt"/>

<property name="responseXslt" value="/WEB-INF/oldResponses.xslt"/>

</bean>

We are simply transforming requests using /WEB-INF/oldRequests.xslt , and


response messages using
/WEB-INF/oldResponses.xslt . Note that, since
endpoint interceptors are registered at the endpoint mapping level, you can
simply create a
endpoint mapping that applies to the "old style" messages, and add the interceptor to that mapping.
Hence, the
transformation will apply only to these "old style" message.

Of course, you could use the WsConfigurerAdapter approach, as described above,


for the
PayloadTransformingInterceptor as well.

5.6 Handling Exceptions
Spring-WS provides EndpointExceptionResolvers to ease the pain of unexpected
exceptions occurring while your message
is being processed by an endpoint which matched the request.
Endpoint exception resolvers somewhat resemble the exception
mappings that can be
defined in the web application descriptor web.xml .
However, they provide a more flexible way to handle
exceptions. They provide information about what
endpoint was invoked when the exception was thrown. Furthermore, a
programmatic way of handling exceptions
gives you many more options for how to respond appropriately. Rather than expose
the innards of your
application by giving an exception and stack trace, you can handle the exception any way you want, for
example by returning a SOAP fault with a specific fault code and string.

Endpoint exception resolvers are automatically picked up by the MessageDispatcher ,


so no explicit configuration is necessary.

Besides implementing the EndpointExceptionResolver interface, which is only a


matter of implementing the
resolveException(MessageContext, endpoint, Exception)
method, you may also use one of the provided

https://docs.spring.io/spring-ws/docs/2.4.0.RELEASE/reference/htmlsingle/ 40/71
09/03/2022 08:45 Spring Web Services Reference Documentation

implementations.
The simplest implementation is the SimpleSoapExceptionResolver , which just
creates a SOAP 1.1 Server
or SOAP 1.2 Receiver Fault, and uses the exception message as the fault string.
The SimpleSoapExceptionResolver is the
default, but it can be overriden by
explicitly adding another resolver.

5.6.1  SoapFaultMappingExceptionResolver
The SoapFaultMappingExceptionResolver is a more sophisticated implementation.
This resolver enables you to take the
class name of any exception that might be thrown and map it to a
SOAP Fault, like so:

<beans>

<bean id="exceptionResolver"

class="org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver">

<property name="defaultFault" value="SERVER"/>

<property name="exceptionMappings">

<value>

org.springframework.oxm.ValidationFailureException=CLIENT,Invalid request

</value>

</property>

</bean>

</beans>

The key values and default endpoint use the format faultCode,faultString,locale , where
only the fault code is required. If
the fault string is not set, it will default to the exception message.
If the language is not set, it will default to English. The above
configuration will map exceptions of
type ValidationFailureException to a client-side SOAP Fault with a fault string
"Invalid request" , as can be seen in the following response:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

<SOAP-ENV:Body>

<SOAP-ENV:Fault>

<faultcode>SOAP-ENV:Client</faultcode>

<faultstring>Invalid request</faultstring>

</SOAP-ENV:Fault>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

If any other exception occurs, it will return the default fault: a server-side fault with the exception
message as fault string.

5.6.2  SoapFaultAnnotationExceptionResolver
Finally, it is also possible to annotate exception classes with the
@SoapFault annotation, to indicate the SOAP Fault that should
be returned
whenever that exception is thrown. In order for these annotations to be picked up, you need to add the
SoapFaultAnnotationExceptionResolver to your application context.
The elements of the annotation include a fault code
enumeration, fault string or reason, and language.
Here is an example exception:

package samples;

import org.springframework.ws.soap.server.endpoint.annotation.FaultCode;

import org.springframework.ws.soap.server.endpoint.annotation.SoapFault;

@SoapFault(faultCode = FaultCode.SERVER)

public class MyBusinessException extends Exception {

public MyClientException(String message) {

super(message);

Whenever the MyBusinessException is thrown with the constructor string


"Oops!" during endpoint invocation, it will result in
the following response:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

<SOAP-ENV:Body>

https://docs.spring.io/spring-ws/docs/2.4.0.RELEASE/reference/htmlsingle/ 41/71
09/03/2022 08:45 Spring Web Services Reference Documentation
y
<SOAP-ENV:Fault>

<faultcode>SOAP-ENV:Server</faultcode>

<faultstring>Oops!</faultstring>

</SOAP-ENV:Fault>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

5.7 Server-side testing
When it comes to testing your Web service endpoints, there are two possible approaches:

Write Unit Tests, where you provide (mock) arguments for your endpoint to
consume.
The advantage of this approach is that it's quite easy to accomplish (especially for classes
annotated with @Endpoint ); the
disadvantage is that
you are not really testing the exact content of the XML messages that are sent over the wire.
Write Integrations Tests, which do test the contents of the message.

The first approach can easily be accomplished with mocking frameworks such as EasyMock, JMock, etc.
The next section will
focus on writing integration tests, using the test features introduced in Spring
Web Services 2.0.

5.7.1 Writing server-side integration tests


Spring Web Services 2.0 introduced support for creating endpoint integration tests.
In this context, an endpoint is class handles
(SOAP) messages (see Section 5.4, “Endpoints”).

The integration test support lives in the org.springframework.ws.test.server package.


The core class in that package is the
MockWebServiceClient .
The underlying idea is that this client creates a request message, and then sends it over to the
endpoint(s) that are configured in a standard MessageDispatcherServlet
application context (see Section 5.3.1,
“ MessageDispatcherServlet ”).
These endpoints will handle the message, and create a response.
The client then receives this
response, and verifies it against registered expectations.

The typical usage of the MockWebServiceClient is:

1. Create a MockWebServiceClient instance by calling


MockWebServiceClient.createClient(ApplicationContext) or
MockWebServiceClient.createClient(WebServiceMessageReceiver, WebServiceMessageFactory) .
2. Send request messages by calling sendRequest(RequestCreator) ,
possibly by using the default RequestCreator
implementations
provided in RequestCreators (which can be statically imported).
3. Set up response expectations by calling andExpect(ResponseMatcher) ,
possibly by using the default ResponseMatcher
implementations
provided in ResponseMatchers (which can be statically imported).
Multiple expectations can be set up by
chaining
andExpect(ResponseMatcher) calls.

Note that the MockWebServiceClient (and related classes) offers a


'fluent' API, so you can typically use the
Code Completion features (i.e. ctrl-space) in your IDE
to guide you through the process of setting up the mock
server.

Also note that you rely on the standard logging features available in Spring Web Services in your
unit tests.
Sometimes it might be useful to inspect the request or response message to find out why a
particular tests failed.
See Section 4.4, “Message Logging and Tracing” for more information.

Consider, for example, this simple Web service endpoint class:

import org.springframework.ws.server.endpoint.annotation.Endpoint;

import org.springframework.ws.server.endpoint.annotation.RequestPayload;

import org.springframework.ws.server.endpoint.annotation.ResponsePayload;

@Endpoint
public class CustomerEndpoint {

https://docs.spring.io/spring-ws/docs/2.4.0.RELEASE/reference/htmlsingle/ 42/71
09/03/2022 08:45 Spring Web Services Reference Documentation

@ResponsePayload
public CustomerCountResponse getCustomerCount(
@RequestPayload CustomerCountRequest request) {
CustomerCountResponse response = new CustomerCountResponse();

response.setCustomerCount(10);

return response;

The CustomerEndpoint in annotated with


@Endpoint .
See Section 5.4, “Endpoints”.
The getCustomerCount() method takes a
CustomerCountRequest as argument, and returns a
CustomerCountResponse .
Both of these classes are objects supported by a marshaller.
For instance, they can have a
@XmlRootElement annotation
to be supported by JAXB2.

A typical test for CustomerEndpoint would look like this:

import javax.xml.transform.Source;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.ApplicationContext;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import org.springframework.xml.transform.StringSource;

import org.junit.Before;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.ws.test.server.MockWebServiceClient;
import static org.springframework.ws.test.server.RequestCreators.*;
import static org.springframework.ws.test.server.ResponseMatchers.*;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("spring-ws-servlet.xml")
public class CustomerEndpointIntegrationTest {

@Autowired

private ApplicationContext applicationContext;

private MockWebServiceClient mockClient;

@Before

public void createClient() {

mockClient = MockWebServiceClient.createClient(applicationContext);
}

@Test

public void customerEndpoint() throws Exception {

Source requestPayload = new StringSource(

"<customerCountRequest xmlns='http://springframework.org/spring-ws'>" +

"<customerName>John Doe</customerName>" +

"</customerCountRequest>");

Source responsePayload = new StringSource(

"<customerCountResponse xmlns='http://springframework.org/spring-ws'>" +

"<customerCount>10</customerCount>" +

"</customerCountResponse>");

mockClient.sendRequest(withPayload(requestPayload)).
andExpect(payload(responsePayload));
}

The CustomerEndpointIntegrationTest imports the


MockWebServiceClient , and statically imports

https://docs.spring.io/spring-ws/docs/2.4.0.RELEASE/reference/htmlsingle/ 43/71
09/03/2022 08:45 Spring Web Services Reference Documentation

RequestCreators and ResponseMatchers .


This test uses the standard testing facilities provided in the Spring Framework.
This is not required, but is generally the
easiest way to set up the test.
The application context is a standard Spring-WS application context (see
Section 5.3.1, “ MessageDispatcherServlet ”),
read from
spring-ws-servlet.xml .
In this case, the application context will contain a bean definition for
CustomerEndpoint (or a perhaps a
<context:component-scan /> is used).
In a @Before method, we create a
MockWebServiceClient by using the
createClient factory method.
We send a request by calling sendRequest() with a
withPayload() RequestCreator
provided by the statically
imported RequestCreators (see Section 5.7.2, “ RequestCreator and RequestCreators ”).
We also set up response expectations by calling andExpect() with a
payload() ResponseMatcher provided
by the
statically imported ResponseMatchers (see Section 5.7.3, “ ResponseMatcher and ResponseMatchers ”).
This part of the test might look a bit confusing, but the Code Completion features of your
IDE are of great help.
After typing
sendRequest( , simply type ctrl-space, and your IDE
will provide you with a list of possible request creating strategies,
provided you
statically imported RequestCreators .
The same applies to andExpect( , provided you statically imported
ResponseMatchers .

5.7.2  RequestCreator and RequestCreators


Initially, the MockWebServiceClient will need to create a request message for the
endpoint to consume.
The client uses the
RequestCreator
strategy interface for this purpose:

public interface RequestCreator {

WebServiceMessage createRequest(WebServiceMessageFactory messageFactory)

throws IOException;

You can write your own implementations of this interface, creating a request message
by using the message factory, but you
certainly do not have to.
The RequestCreators class provides a way to create a
RequestCreator based on a given payload
in the
withPayload() method.
You will typically statically import RequestCreators .

5.7.3  ResponseMatcher and ResponseMatchers


When the request message has been processed by the endpoint, and a response has been received,
the
MockWebServiceClient can verify whether this response message meets certain
expectations.
The client uses the
ResponseMatcher strategy interface for this purpose:

public interface ResponseMatcher {

void match(WebServiceMessage request,

WebServiceMessage response)

throws IOException, AssertionError;

Once again you can write your own implementations of this interface, throwing
AssertionError s when the message does not
meet your expectations, but you
certainly do not have to, as the ResponseMatchers class provides standard
ResponseMatcher implementations for you to use in your tests.
You will typically statically import this class.

The ResponseMatchers class provides the following response matchers:

ResponseMatchers method Description

payload() Expects a given response payload.

Expects the response payload to validate


validPayload()
against given XSD schema(s).

https://docs.spring.io/spring-ws/docs/2.4.0.RELEASE/reference/htmlsingle/ 44/71
09/03/2022 08:45 Spring Web Services Reference Documentation

ResponseMatchers method Description

Expects a given XPath expression to exist, not


xpath()
exist, or evaluate to a given
value.

Expects a given SOAP header to exist in the


soapHeader()
response message.

Expects that the response message does not


noFault()
contain a SOAP Fault.

mustUnderstandFault() ,
clientOrSenderFault() , Expects the response message to contain a
serverOrReceiverFault() , and
versionMismatchFault() specific SOAP Fault.

You can set up multiple response expectations by chaining andExpect() calls,


like so:

mockClient.sendRequest(...).

andExpect(payload(expectedResponsePayload)).

andExpect(validPayload(schemaResource));

For more information on the response matchers provided by ResponseMatchers ,


refer to the class level Javadoc.

[2] For more information on WS-Addressing, see http://en.wikipedia.org/wiki/WS-Addressing.

6. Using Spring Web Services on the Client

6.1 Introduction
Spring-WS provides a client-side Web service API that allows for consistent, XML-driven access to
Web services. It also caters
for the use of marshallers and unmarshallers
so that your service tier code can deal exclusively with Java objects.

The org.springframework.ws.client.core package provides the core functionality


for using the client-side access API. It contains
template classes that simplify the use of Web
services, much like the core Spring JdbcTemplate does for JDBC. The
design
principle common to Spring template classes is to provide helper methods to perform common
operations, and for more
sophisticated usage, delegate to user implemented callback interfaces.
The Web service template follows the same design. The
classes offer various convenience methods
for the sending and receiving of XML messages, marshalling objects to XML before
sending, and
allows for multiple transport options.

6.2 Using the client-side API

6.2.1  WebServiceTemplate
The WebServiceTemplate is the core class for client-side Web service
access in Spring-WS. It contains methods for sending
Source objects,
and receiving response messages as either Source or
Result . Additionally, it can marshal objects to XML
before sending
them across a transport, and unmarshal any response XML into an object again.

URIs and Transports

The WebServiceTemplate class uses an URI as the message destination.


You can either set a defaultUri property on the
template itself,
or supply an URI explicitly when calling a method on the template. The URI will be
resolved into a
WebServiceMessageSender , which is
responsible for sending the XML message across a transport layer. You can set one or
more message senders using the messageSender or
messageSenders properties of the
WebServiceTemplate class.

HTTP transports

https://docs.spring.io/spring-ws/docs/2.4.0.RELEASE/reference/htmlsingle/ 45/71
09/03/2022 08:45 Spring Web Services Reference Documentation

There are two implementations of the WebServiceMessageSender


interface for sending messages via HTTP. The default
implementation is the
HttpUrlConnectionMessageSender , which uses the facilities provided
by Java itself. The alternative is
the HttpComponentsMessageSender ,
which uses the
Apache HttpComponents HttpClient.
Use the latter if you need more
advanced and easy-to-use functionality (such as authentication,
HTTP connection pooling, and so forth).

To use the HTTP transport, either set the defaultUri to something like
http://example.com/services , or supply the uri
parameter
for one of the methods.

The following example shows how the default configuration can be used for HTTP transports:

<beans>

<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>

<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">

<constructor-arg ref="messageFactory"/>

<property name="defaultUri" value="http://example.com/WebService"/>

</bean>

</beans>

The following example shows how override the default configuration, and to use Apache HttpClient to
authenticate using HTTP
authentication:

<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">

<constructor-arg ref="messageFactory"/>

<property name="messageSender">

<bean class="org.springframework.ws.transport.http.HttpComponentsMessageSender">

<property name="credentials">

<bean class="org.apache.http.auth.UsernamePasswordCredentials">

<constructor-arg value="john:secret"/>

</bean>

</property>

</bean>

</property>

<property name="defaultUri" value="http://example.com/WebService"/>

</bean>

JMS transport

For sending messages over JMS, Spring Web Services provides the
JmsMessageSender . This class uses the facilities of the
Spring framework
to transform the WebServiceMessage into a JMS
Message , send it on its way on a
Queue or Topic , and
receive a
response (if any).

To use the JmsMessageSender , you need to set the


defaultUri or uri parameter to a JMS URI, which - at a
minimum - consists
of the jms: prefix and a destination name. Some examples of
JMS URIs are: jms:SomeQueue ,
jms:SomeTopic?priority=3&deliveryMode=NON_PERSISTENT , and
jms:RequestQueue?replyToName=ResponseName .
For
more information on this URI syntax, refer to the class level Javadoc of the
JmsMessageSender .

By default, the JmsMessageSender send JMS


BytesMessage , but
this can be overriden to use TextMessages by using the
messageType parameter on the JMS URI. For example:
jms:Queue?messageType=TEXT_MESSAGE .
Note that
BytesMessages are the preferred type, because
TextMessages do not support attachments and character
encodings reliably.

The following example shows how to use the JMS transport in combination with an ActiceMQ
connection factory:

<beans>

<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>

<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">

<property name="brokerURL" value="vm://localhost?broker.persistent=false"/>

</bean>

<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">

https://docs.spring.io/spring-ws/docs/2.4.0.RELEASE/reference/htmlsingle/ 46/71
09/03/2022 08:45 Spring Web Services Reference Documentation
p g p g p
<constructor-arg ref="messageFactory"/>

<property name="messageSender">

<bean class="org.springframework.ws.transport.jms.JmsMessageSender">

<property name="connectionFactory" ref="connectionFactory"/>

</bean>

</property>

<property name="defaultUri" value="jms:RequestQueue?deliveryMode=NON_PERSISTENT"/>

</bean>

</beans>

Email transport
Spring Web Services also provides an email transport, which can be used to send web service
messages via SMTP, and retrieve
them via either POP3 or IMAP. The client-side email
functionality is contained in the MailMessageSender class.
This class
creates an email message from the request
WebServiceMessage , and sends it via SMTP. It then waits for a
response message
to arrive in the incoming POP3 or IMAP server.

To use the MailMessageSender , set the defaultUri or


uri parameter to a mailto URI. Here are some URI
examples:
mailto:john@example.com , and
mailto:server@localhost?subject=SOAP%20Test . Make sure that the message sender
is
properly configured with a transportUri, which indicates the server to use for
sending requests (typically a SMTP server), and a
storeUri, which indicates
the server to poll for responses (typically a POP3 or IMAP server).

The following example shows how to use the email transport:

<beans>

<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>

<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">

<constructor-arg ref="messageFactory"/>

<property name="messageSender">

<bean class="org.springframework.ws.transport.mail.MailMessageSender">

<property name="from" value="Spring-WS SOAP Client &lt;client@example.com&gt;"/>

<property name="transportUri" value="smtp://client:s04p@smtp.example.com"/>

<property name="storeUri" value="imap://client:s04p@imap.example.com/INBOX"/>

</bean>

</property>

<property name="defaultUri" value="mailto:server@example.com?subject=SOAP%20Test"/>

</bean>

</beans>

XMPP transport

Spring Web Services 2.0 introduced an XMPP (Jabber) transport, which can be used to send and
receive web service messages
via XMPP. The client-side XMPP
functionality is contained in the XmppMessageSender class.
This class creates an XMPP
message from the request
WebServiceMessage , and sends it via XMPP. It then listens for a
response message to arrive.

To use the XmppMessageSender , set the defaultUri or


uri parameter to a xmpp URI, for example
xmpp:johndoe@jabber.org . The sender also requires an
XMPPConnection to work, which can be conveniently created using
the
org.springframework.ws.transport.xmpp.support.XmppConnectionFactoryBean .

The following example shows how to use the xmpp transport:

<beans>

<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>

<bean id="connection" class="org.springframework.ws.transport.xmpp.support.XmppConnectionFactoryBean">

<property name="host" value="jabber.org"/>

<property name="username" value="username"/>

<property name="password" value="password"/>

</bean>
https://docs.spring.io/spring-ws/docs/2.4.0.RELEASE/reference/htmlsingle/ 47/71
09/03/2022 08:45 Spring Web Services Reference Documentation
</bea >

<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">

<constructor-arg ref="messageFactory"/>

<property name="messageSender">

<bean class="org.springframework.ws.transport.xmpp.XmppMessageSender">

<property name="connection" ref="connection"/>

</bean>

</property>

<property name="defaultUri" value="xmpp:user@jabber.org"/>

</bean>

</beans>

Message factories

In addition to a message sender, the WebServiceTemplate requires a Web


service message factory. There are two message
factories for SOAP:
SaajSoapMessageFactory and AxiomSoapMessageFactory .
If no message factory is specified (via the
messageFactory property),
Spring-WS will use the SaajSoapMessageFactory by default.

6.2.2 Sending and receiving a WebServiceMessage


The WebServiceTemplate contains many convenience methods to send and receive
web service messages. There are
methods that accept and return a Source
and those that return a Result . Additionally, there are methods which
marshal and
unmarshal objects to XML. Here is an example that sends a simple XML message to a Web
service.

import java.io.StringReader;

import javax.xml.transform.stream.StreamResult;

import javax.xml.transform.stream.StreamSource;

import org.springframework.ws.WebServiceMessageFactory;

import org.springframework.ws.client.core.WebServiceTemplate;

import org.springframework.ws.transport.WebServiceMessageSender;

public class WebServiceClient {

private static final String MESSAGE =

"<message xmlns=\"http://tempuri.org\">Hello Web Service World</message>";

private final WebServiceTemplate webServiceTemplate = new WebServiceTemplate();

public void setDefaultUri(String defaultUri) {

webServiceTemplate.setDefaultUri(defaultUri);

// send to the configured default URI

public void simpleSendAndReceive() {

StreamSource source = new StreamSource(new StringReader(MESSAGE));

StreamResult result = new StreamResult(System.out);

webServiceTemplate.sendSourceAndReceiveToResult(source, result);

// send to an explicit URI

public void customSendAndReceive() {

StreamSource source = new StreamSource(new StringReader(MESSAGE));

StreamResult result = new StreamResult(System.out);

webServiceTemplate.sendSourceAndReceiveToResult("http://localhost:8080/AnotherWebService",

source, result);

<beans xmlns="http://www.springframework.org/schema/beans">

https://docs.spring.io/spring-ws/docs/2.4.0.RELEASE/reference/htmlsingle/ 48/71
09/03/2022 08:45 Spring Web Services Reference Documentation
<bean id="webServiceClient" class="WebServiceClient">

<property name="defaultUri" value="http://localhost:8080/WebService"/>

</bean>

</beans>

The above example uses the WebServiceTemplate to send a hello


world message to the web service located at
http://localhost:8080/WebService
(in the case of the simpleSendAndReceive() method),
and writes the result to the
console. The WebServiceTemplate is
injected with the default URI, which is used because no URI was supplied explicitly
in the
Java code.

Please note that the WebServiceTemplate class is thread-safe once


configured (assuming that all of it's dependencies are
thread-safe too, which is the case for
all of the dependencies that ship with Spring-WS), and so multiple objects can use the
same
shared WebServiceTemplate instance if so desired.
The WebServiceTemplate exposes a zero argument constructor
and
messageFactory/messageSender bean properties which
can be used for constructing the instance (using a Spring container
or plain Java code).
Alternatively, consider deriving from Spring-WS's WebServiceGatewaySupport
convenience base class,
which exposes convenient bean properties to enable easy configuration.
(You do not have to extend this base class... it is
provided as a convenience
class only.)

6.2.3 Sending and receiving POJOs - marshalling and unmarshalling


In order to facilitate the sending of plain Java objects, the
WebServiceTemplate has a number of send(..) methods
that take
an Object as an argument for a message's data content.
The method marshalSendAndReceive(..) in the
WebServiceTemplate class delegates the conversion of the request object
to XML to a Marshaller , and the conversion of
the response
XML to an object to an Unmarshaller . (For more information
about marshalling and unmarshaller, refer to
the
Spring documentation.)
By using the
marshallers, your application code can focus on the business object that is being sent or
received and not be concerned with the details of how it is represented as XML. In order to
use the marshalling functionality, you
have to set a marshaller and unmarshaller with the
marshaller/unmarshaller properties of the
WebServiceTemplate class.

6.2.4 
WebServiceMessageCallback
To accommodate the setting of SOAP headers and other settings on the message, the
WebServiceMessageCallback interface
gives you access to the
message after it has been created, but before it
is sent. The example below demonstrates how to set the
SOAP Action header on a message
that is created by marshalling an object.

public void marshalWithSoapActionHeader(MyObject o) {

webServiceTemplate.marshalSendAndReceive(o, new WebServiceMessageCallback() {

public void doWithMessage(WebServiceMessage message) {

((SoapMessage)message).setSoapAction("http://tempuri.org/Action");

});

Note that you can also use the


org.springframework.ws.soap.client.core.SoapActionCallback to set the
SOAP
Action header.

WS-Addressing
In addition to the server-side WS-Addressing support,
Spring Web Services also has support for this specification on the client-
side.

For setting WS-Addressing headers on the client, you can use the
org.springframework.ws.soap.addressing.client.ActionCallback . This callback
takes the desired Action header as a
parameter. It also has constructors for specifying the
WS-Addressing version, and a To header. If not specified, the
To header
will default to the URL of the connection being made.

https://docs.spring.io/spring-ws/docs/2.4.0.RELEASE/reference/htmlsingle/ 49/71
09/03/2022 08:45 Spring Web Services Reference Documentation

Here is an example of setting the Action header to


http://samples/RequestOrder :

webServiceTemplate.marshalSendAndReceive(o, new ActionCallback("http://samples/RequestOrder"));

6.2.5 
WebServiceMessageExtractor
The WebServiceMessageExtractor interface is a low-level
callback interface that allows you to have full control over the
process to extract an
Object from a received WebServiceMessage .
The WebServiceTemplate will invoke the
extractData(..)
method on a supplied WebServiceMessageExtractor
while the underlying connection to the serving
resource is still open.
The following example illustrates the WebServiceMessageExtractor
in action:

public void marshalWithSoapActionHeader(final Source s) {

final Transformer transformer = transformerFactory.newTransformer();

webServiceTemplate.sendAndReceive(new WebServiceMessageCallback() {

public void doWithMessage(WebServiceMessage message) {

transformer.transform(s, message.getPayloadResult());

},

new WebServiceMessageExtractor() {

public Object extractData(WebServiceMessage message) throws IOException

// do your own transforms with message.getPayloadResult()

// or message.getPayloadSource()

});

6.3 Client-side testing
When it comes to testing your Web service clients (i.e. classes that uses the
WebServiceTemplate to access a Web service),
there are two possible
approaches:

Write Unit Tests, which simply mock away the


WebServiceTemplate class,
WebServiceOperations interface, or the
complete client class.
The advantage of this approach is that it's quite easy to accomplish; the disadvantage is that
you are not really testing the
exact content of the XML messages that are sent over the wire,
especially when mocking out the entire client class.
Write Integrations Tests, which do test the contents of the message.

The first approach can easily be accomplished with mocking frameworks such as EasyMock, JMock, etc.
The next section will
focus on writing integration tests, using the test features introduced in Spring
Web Services 2.0.

6.3.1 Writing client-side integration tests


Spring Web Services 2.0 introduced support for creating Web service client integration tests.
In this context, a client is a class
that uses the WebServiceTemplate
to access a Web service.

The integration test support lives in the org.springframework.ws.test.client package.


The core class in that package is the
MockWebServiceServer .
The underlying idea is that the web service template connects to this mock server, sends it request
message, which the mock server then verifies against the registered expectations.
If the expectations are met, the mock server
then prepares a response message, which is send back to the
template.

The typical usage of the MockWebServiceServer is:

1. Create a MockWebServiceServer instance by calling


MockWebServiceServer.createServer(WebServiceTemplate) ,
MockWebServiceServer.createServer(WebServiceGatewaySupport) , or
MockWebServiceServer.createServer(ApplicationContext) .
2. Set up request expectations by calling expect(RequestMatcher) ,
possibly by using the default RequestMatcher
implementations
provided in RequestMatchers (which can be statically imported).
Multiple expectations can be set up by
chaining
andExpect(RequestMatcher) calls.

https://docs.spring.io/spring-ws/docs/2.4.0.RELEASE/reference/htmlsingle/ 50/71

You might also like