xmlspringsoapwebservicetemplate

How to fix an invalid XML so it can be consumed by Spring WebServiceTemplate


I'm using Spring's WebServiceTemplate to consume a Soap service. Once in a while this Soap service responds with an invalid XML. I would like to intercept its parser and fix the invalid XML before it is parsed. How could I do that? Right now I'm calling:

wsTemplate.sendSourceAndReceiveToResult(new StreamSource(new StringInputStream(msg)),new StreamResult(stringWriter))

I suppose I have to call sendSourceAndReceive and define my own SourceExtractor but that seems like I'm meddling too much on the process when I actually wanted to do something simple.

This is the problem I want to fix:

An invalid XML character (Unicode: 0x1f) was found in the element content of the document.

SystemErr     R    at org.springframework.ws.soap.saaj.SaajSoapMessageFactory.createWebServiceMessage(SaajSoapMessageFactory.java :210)

That character is accepted in XML 1.1 but the document is described as XML 1.0:

<?xml version="1.0" encoding="utf-8"?>

So what I want is to replace that character for a tab or a space.


Solution

  • I was able to fix the message before it's parsed by decorating the webServiceTemplate's WebServiceMessageFactory as follows:

    final WebServiceMessageFactory mfOriginal = myWebServiceTemplate.getMessageFactory();
    WebServiceMessageFactory mfDecorator = new WebServiceMessageFactory() {
        @Override
        public WebServiceMessage createWebServiceMessage(final InputStream inputStream) throws InvalidXmlException, IOException {
            InputStream decoratedIs = new InputStream() {
    
                @Override
                public int read() throws IOException {
                    int nextByte = inputStream.read();
                    // Replacing the invalid character with a tab. Touching nothing else.
                    if (nextByte == 0x1f) {
                        nextByte = 0x09;
                    }
                    return nextByte;
                }
            };
            return mfOriginal.createWebServiceMessage(decoratedIs);
        }
    
        @Override
        public WebServiceMessage createWebServiceMessage() {
            return mfOriginal.createWebServiceMessage();
        }
    };
    myServiceTemplate.setMessageFactory(mfDecorator);