Search code examples
javaxmlspringspring-bootsoap

How do I intercept a Soap Response XML with invalid character


The error is as follows: [com.ctc.wstx.exc.WstxLazyException] Illegal character entity: expansion character (code 0x1a\r\n at [row,col {unknown-source}]: [1,8035]

This is my WebService in Springboot with its WebMethod which receives an array of Polizas from which one of its fields contains an invalid character:

@WebService(targetNamespace = "http://example.org.co/", name = "PolizaSoap")
@XmlSeeAlso({ObjectFactory.class})
public interface PolizaSoap {

@WebMethod(operationName = "Polizas", action = "http://example.org.co/Polizas")
@RequestWrapper(localName = "Polizas", targetNamespace = "http://example.org.co/", className = "com.example.Polizas")
@ResponseWrapper(localName = "PolizasResponse", targetNamespace = "http://example.org.co/", className = "com.example.PolizasResponse")
@WebResult(name = "PolizasResult", targetNamespace = "http://example.org.co/")
public ArrayOfPolizas Polizas(
    @WebParam(name = "param1", targetNamespace = "http://example.org.co/")
    java.lang.String param1,
    @WebParam(name = "param2", targetNamespace = "http://example.org.co/")
    java.lang.String param2,
    @WebParam(name = "param3", targetNamespace = "http://example.org.co/")
    java.lang.String param3
);
}

I have tried all kinds of interceptor (ClientInterceptor), filters (WebFilter), handler (SOAPHandler, HandlerInterceptor) and none have worked for me, the error occurs instantly and I have not found a way to obtain the XML response with the invalid character to be able to modify it and so everything works.

I'm beginning to think it's impossible to do, is there any other alternative that doesn't involve asking the response provider to correct it?. How can I intercept a XML response with invalid character (0x1a) without/before trigger a WebServiceException?

EDIT: Does anyone know if it is possible to use a FilterInputStream to correct the "XML" that comes with invalid characters before throwing an exception?


Solution

  • If you call an external SOAP service and you get invalid XML as a response and there is no chance of getting the provider to fix its error, then the only option you have is to forgo the standard SOAP libraries and call the service using low-level HTTP functions, treat the response as plain text and fix the error, and then parse the corrected XML yourself.

    Here is an example to call a SOAP service without SOAP libraries (taken from https://technology.amis.nl/soa/how-to-call-a-call-a-webservice-directly-from-java-without-webservice-library/ )

    public String getWeather(String city) throws MalformedURLException, IOException {
      //Code to make a webservice HTTP request
      String responseString = "";
      String outputString = "";
      String wsURL = "http://www.deeptraining.com/webservices/weather.asmx";
      URL url = new URL(wsURL);
      URLConnection connection = url.openConnection();
      HttpURLConnection httpConn = (HttpURLConnection)connection;
      ByteArrayOutputStream bout = new ByteArrayOutputStream();
      String xmlInput =
        " <soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:web=\"http://litwinconsulting.com/webservices/\">\n" +
        " <soapenv:Header/>\n" +
        " <soapenv:Body>\n" +
        " <web:GetWeather>\n" +
        " <!--Optional:-->\n" +
        " <web:City>" + city + "</web:City>\n" +
        " </web:GetWeather>\n" +
        " </soapenv:Body>\n" +
        " </soapenv:Envelope>";
       
      byte[] buffer = new byte[xmlInput.length()];
      buffer = xmlInput.getBytes();
      bout.write(buffer);
      byte[] b = bout.toByteArray();
      String SOAPAction = "http://litwinconsulting.com/webservices/GetWeather";
    
      // Set the appropriate HTTP parameters.
      httpConn.setRequestProperty("Content-Length",
      String.valueOf(b.length));
      httpConn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
      httpConn.setRequestProperty("SOAPAction", SOAPAction);
      httpConn.setRequestMethod("POST");
      httpConn.setDoOutput(true);
      httpConn.setDoInput(true);
      OutputStream out = httpConn.getOutputStream();
    
      //Write the content of the request to the outputstream of the HTTP Connection.
      out.write(b);
      out.close();
      //Ready with sending the request.
       
      //Read the response.
      InputStreamReader isr =
      new InputStreamReader(httpConn.getInputStream());
      BufferedReader in = new BufferedReader(isr);
       
      //Write the SOAP message response to a String.
      while ((responseString = in.readLine()) != null) {
        outputString = outputString + responseString;
      }
      
      //**************************************************************************************************** 
      // Here you have the response as plain text and you can apply your corrections
      //**************************************************************************************************** 
    
      //Parse the String output to a org.w3c.dom.Document and be able to reach every node with the org.w3c.dom API.
      Document document = parseXmlFile(outputString);
      NodeList nodeLst = document.getElementsByTagName("GetWeatherResult");
      String weatherResult = nodeLst.item(0).getTextContent();
      System.out.println("Weather: " + weatherResult);
       
      return weatherResult;
    }