0

I'm writing a SOAP client against a server that's producing a Fault that is not up-to-spec. Specifically, the lang attribute is missing in the Text element in the Fault Reason (spec). I'm using Spring WS 2.4.0. Is there a way to intercept the response and inject the attribute before it gets parsed into a SaajSoapMessage? I tried creating a ClientInterceptor, but the xml has already been parsed by the time it hits the interceptor. Would I need to create my own MessageFactory?

end-user
  • 2,845
  • 6
  • 30
  • 56

1 Answers1

1

I've solved this with help from this answer and this answer.

When I instantiated my WebServiceGatewaySupport, I added a ClientInterceptor where I configured the handleFault() method:

@Override
public boolean handleFault(MessageContext messageContext) throws WebServiceClientException {
    LOGGER.debug("intercepted a fault.");
    TransformerFactory transformerFactory = TransformerFactory.newInstance();
    WebServiceMessage response = messageContext.getResponse();
    Source source = response.getPayloadSource();
    StreamResult streamResult = new StreamResult(new StringWriter());

    try {
        Transformer displayTransformer = transformerFactory.newTransformer();
        displayTransformer.transform(source, streamResult);
        LOGGER.debug("\t>> initial response\n" + streamResult.getWriter().toString());

        StreamSource xslSource = new StreamSource(new File(
                FaultInterceptor.class.getResource("/SoapFaultFix.xsl").getFile()
        ));
        Transformer modifyingTransformer = transformerFactory.newTransformer(xslSource);
        modifyingTransformer.transform(source, response.getPayloadResult());

    } catch (TransformerException e) {
        e.printStackTrace();
    }

    return true;
}

This simply takes the source xml and runs it through an xsl transformation. It's important to begin with an identity transformation so you don't lose content. I then added the attribute and value, then dropped in the existing value. My SoapFaultFix.xsl looked like this:

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"
>
    <xsl:template match="/ | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="//soapenv:Fault/soapenv:Reason/soapenv:Text">
        <soapenv:Text>
            <xsl:attribute name="xml:lang">en</xsl:attribute>
            <xsl:value-of select="."/>
        </soapenv:Text>
    </xsl:template>
</xsl:stylesheet>

I liked this approach because I found drilling into the DOM was arduous with pure Java, and I could easily expand the xsl to make other changes.

Community
  • 1
  • 1
end-user
  • 2,845
  • 6
  • 30
  • 56