Search code examples
springweb-servicessoapspring-wshttp-status-codes

Spring WS (DefaultWsdl11Definition) HTTP status code with void


We have a (working) SOAP web service based on Spring WS with DefaultWsdl11Definition.

This is basically what it looks like:

@Endpoint("name")
public class OurEndpoint {

    @PayloadRoot(namespace = "somenamespace", localPart = "localpart")
    public void onMessage(@RequestPayload SomePojo pojo) {
        // do stuff
    }
}

It is wired in Spring and it is correctly processing all of our SOAP requests. The only problem is that the method returns a 202 Accepted. This is not what the caller wants, he'd rather have us return 204 No Content (or if that is not possible an empty 200 OK).

Our other endpoints have a valid response object, and do return 200 OK. It seems void causes 202 when 204 might be more appropriate?

Is it possible to change the response code in Spring WS? We can't seem to find the correct way to do this.

Things we tried and didn't work:

  • Changing the return type to:
    • HttpStatus.NO_CONTENT
    • org.w3c.dom.Element <- not accepted
  • Adding @ResponseStatus <- this is for MVC, not WS

Any ideas?


Solution

  • When finding a proper solutions we've encountered some ugly problems:

    • Creating custom adapters/interceptors is problematic because the handleResponse method isn't called by Spring when you don't have a response (void)
    • Manually setting the status code doesn't work because HttpServletConnection keeps a boolean statusCodeSet which doesn't get updated

    But luckily we managed to get it working with the following changes:

    /**
     * If a web service has no response, this handler returns: 204 No Content
     */
    public class NoContentInterceptor extends EndpointInterceptorAdapter {
    
        @Override
        public void afterCompletion(MessageContext messageContext, Object o, Exception e) throws Exception {
            if (!messageContext.hasResponse()) {
                TransportContext tc = TransportContextHolder.getTransportContext();
                if (tc != null && tc.getConnection() instanceof HttpServletConnection) {
                    HttpServletConnection connection = ((HttpServletConnection) tc.getConnection());
                    // First we force the 'statusCodeSet' boolean to true:
                    connection.setFaultCode(null);
                    // Next we can set our custom status code:
                    connection.getHttpServletResponse().setStatus(204);
                }
            }
        }
    }
    

    Next we need to register this interceptor, this can be easily done using Spring's XML:

    <sws:interceptors>
        <bean class="com.something.NoContentInterceptor"/>
    </sws:interceptors>
    

    A big thanks to @m-deinum for pointing us in the right direction!