Spring-WS Dev Guide
Spring-WS Dev Guide
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.”
<bean id="validatingInterceptor"
class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
</bean>
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">
</bean>
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.
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="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)
super(message);
<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.
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.
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;
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
@Before
mockClient = MockWebServiceClient.createClient(applicationContext);
}
@Test
"<customerCountRequest xmlns='http://springframework.org/spring-ws'>" +
"<customerName>John Doe</customerName>" +
"</customerCountRequest>");
"<customerCountResponse xmlns='http://springframework.org/spring-ws'>" +
"<customerCount>10</customerCount>" +
"</customerCountResponse>");
mockClient.sendRequest(withPayload(requestPayload)).
andExpect(payload(responsePayload));
}
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
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 .
WebServiceMessage response)
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.
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
mustUnderstandFault() ,
clientOrSenderFault() , Expects the response message to contain a
serverOrReceiverFault() , and
versionMismatchFault() specific SOAP Fault.
mockClient.sendRequest(...).
andExpect(payload(expectedResponsePayload)).
andExpect(validPayload(schemaResource));
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.
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.
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
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>
<constructor-arg ref="messageFactory"/>
</bean>
</beans>
The following example shows how override the default configuration, and to use Apache HttpClient to
authenticate using HTTP
authentication:
<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>
</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).
The following example shows how to use the JMS transport in combination with an ActiceMQ
connection factory:
<beans>
</bean>
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">
</bean>
</property>
</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.
<beans>
<constructor-arg ref="messageFactory"/>
<property name="messageSender">
<bean class="org.springframework.ws.transport.mail.MailMessageSender">
</bean>
</property>
</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.
<beans>
</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 >
<constructor-arg ref="messageFactory"/>
<property name="messageSender">
<bean class="org.springframework.ws.transport.xmpp.XmppMessageSender">
</bean>
</property>
</bean>
</beans>
Message factories
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;
webServiceTemplate.setDefaultUri(defaultUri);
webServiceTemplate.sendSourceAndReceiveToResult(source, result);
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">
</bean>
</beans>
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.
((SoapMessage)message).setSoapAction("http://tempuri.org/Action");
});
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
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:
webServiceTemplate.sendAndReceive(new WebServiceMessageCallback() {
transformer.transform(s, message.getPayloadResult());
},
new WebServiceMessageExtractor() {
// 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:
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.
https://docs.spring.io/spring-ws/docs/2.4.0.RELEASE/reference/htmlsingle/ 50/71