Spring-WS client not setting SOAPAction header

soap, soap-client, spring-ws

Solution

I worked this out but never posted the answer. Here's what I ended up with that works well:

public WebServiceTemplate getWebServiceTemplate() throws SOAPException {
  if (webServiceTemplate == null) {
    final MessageFactory msgFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
    final SaajSoapMessageFactory newSoapMessageFactory = new SaajSoapMessageFactory(msgFactory);
    webServiceTemplate = new WebServiceTemplate(newSoapMessageFactory);
  }   

  return webServiceTemplate;
}

public Object sendReceive(Object requestObject, ArrayList<String> classesToMarshall, final String action)
        throws ClassNotFoundException, SoapFaultException, SoapFaultClientException, WebServiceTransportException,
        IllegalStateException, SOAPException {

  final WebServiceTemplate wst = getWebServiceTemplate();

    final SoapMarshallUtil smu = getSoapMarshallUtil();
    smu.configureMarshaller(wst, classesToMarshall);

    // soap 1.2
    SoapActionCallback requestCallback = new SoapActionCallback(action) {
        public void doWithMessage(WebServiceMessage message) {
            SaajSoapMessage soapMessage = (SaajSoapMessage) message;
            SoapHeader soapHeader = soapMessage.getSoapHeader();

            QName wsaToQName = new QName("http://www.w3.org/2005/08/addressing", "To", "wsa");
            SoapHeaderElement wsaTo =  soapHeader.addHeaderElement(wsaToQName);
            wsaTo.setText(uri);

            QName wsaActionQName = new QName("http://www.w3.org/2005/08/addressing", "Action", "wsa");
            SoapHeaderElement wsaAction =  soapHeader.addHeaderElement(wsaActionQName);
            wsaAction.setText(action);
        }
    };

    Object responseObject = wst.marshalSendAndReceive(this.uri, requestObject, requestCallback);
    return responseObject;
}

Problem

I'm sending a SOAP request and the server is complaining that the SOAPAction header is empty. I think I'm setting it right, but obviously I'm not. Wireshark shows it's not set. ``` @Test public void testLogin() throws Exception { StringBuffer loginXml = new StringBuffer(); loginXml.append("<soapenv:Envelope xmlns:soapenv=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:ns=\"http://example.com/xyz/2010/08\">"); loginXml.append(" <soapenv:Header>"); loginXml.append(" <ns:loginOperationDetails>"); loginXml.append(" </ns:loginOperationDetails>"); loginXml.append(" </soapenv:Header>"); loginXml.append(" <soapenv:Body>"); loginXml.append(" <ns:LogIn>"); loginXml.append(" <ns:logInInfo>"); loginXml.append(" <ns:CustomerAccountId>customer1</ns:CustomerAccountId>"); loginXml.append(" <ns:Username>JDoe</ns:Username>"); loginXml.append(" <ns:Password>abc123</ns:Password>"); loginXml.append(" </ns:logInInfo>"); loginXml.append(" </ns:LogIn>"); loginXml.append(" </soapenv:Body>"); loginXml.append("</soapenv:Envelope>"); WebServiceTemplate webServiceTemplate = new WebServiceTemplate(); MessageFactory msgFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL); SaajSoapMessageFactory newSoapMessageFactory = new SaajSoapMessageFactory(msgFactory); webServiceTemplate.setMessageFactory(newSoapMessageFactory); String uri = "http://xyz.example.com/xyz_1.0/membership.svc/ws"; webServiceTemplate.setDefaultUri(uri); StreamSource source = new StreamSource(new StringReader(loginXml.toString())); StreamResult result = new StreamResult(System.out); boolean resultReturned = false; try { resultReturned = webServiceTemplate.sendSourceAndReceiveToResult(source, new SoapActionCallback("http://example.com/xyz/2010/08/MembershipService/LogIn"), result); } catch (SoapFaultClientException sfe) { logger.error("SoapFaultClientException resultReturned: " + resultReturned, sfe); fail(); } } ``` The error I'm getting back from the server says: ``` 500 Internal Server Error The SOAP action specified on the message, '', does not match the HTTP SOAP Action, 'http://example.com/xyz/2010/08/MembershipService/LogIn'. ```

Original source