Access Spring WS MessageContext from anywhere


UPDATE (2011-03-27): This article is relevant to those using the 1.5 version of Spring WS. Since version 2.0 it is trivial to access MessageContext by simply declaring it as one of the arguments in the handling method.

Spring Web Services framework has a special MessageContext class for holding request and response messages as well as arbitrary properties during the processing of a WS request. This class is especially useful if you are writing your own endpoint interceptors, because it allows you to do whatever you want with all incoming or outgoing web service messages, regardless of the endpoint in which they are processed.

There is certainly no problem getting to MessageContext in an EndpointInterceptor (all interface methods contain a MessageContext parameter), but what if you need to access it in your endpoint handler? For example, if you had to know the content type of all SOAP attachments that came in request, you would do it like this:

SoapMessage request = (SoapMessage) messageContext.getRequest();
for (Iterator it = request.getAttachments(); it.hasNext();) {
    Attachment attachment = (Attachment);

You could do that in a MessageEndpoint, but not in a PayloadEndpoint where you have no access to MessageContext since it is not passed as parameter to your endpoint method.

Curiously, TransportContext does not have this limitation, as it is bound to current thread and accessible via TransportContextHolder.getTransportContext(). Users of Spring Security will remember that SecurityContext can be accessed in the same manner via SecurityContextHolder.getContext(). Notice a recurring theme here? What we lack in Spring WS is a “MessageContextHolder” class that would allow us to access MessageContext from anywhere in our code. Let’s go ahead and implement this missing utility.

MessageContextHolder is going to be a really simple utility class that can store and retrieve a reference to MessageContext in local thread.

public final class MessageContextHolder {

    private static ThreadLocal<MessageContext> threadLocal =
        new ThreadLocal<MessageContext>() {
            protected MessageContext initialValue() {
                return null;

    private MessageContextHolder() {

    public static MessageContext getMessageContext() {
        return threadLocal.get();

    public static void setMessageContext(MessageContext context) {

    public static void removeMessageContext() {

Next we need an endpoint interceptor that puts MessageContext to “Holder” before WS request is processed, and removes it when WS response (or fault) is about to be sent.

public class MessageContextHolderInterceptor implements EndpointInterceptor {

    public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
        return true;

    public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
        return true;

    public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
        return true;

Finally, we configure whatever EndpointMapping beans we use to include our interceptor:

<bean class="">
    <property name="interceptors">
            <bean class="my.project.MessageContextHolderInterceptor"/>

Now once this interceptor does its job upon each request, you can say MessageContextHolder.getMessageContext() and you’ll get current MessageContext whenever you need it.