0

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?

Olivetz
  • 3
  • 2
  • If the protocol calls for the request to be XML, and what your service receives is not XML, then your ***only*** course of action is to return an error indicating that the request was not well-formed. You should try to do nothing more. – kjhughes Feb 19 '23 at 00:24
  • 1
    I agree with @kjhughes. Your focus should be on detecting bad data, diagnosing where it comes from, and getting it fixed at source. Attempting to repair bad data is ultimately bad for system reliability. If someone is sending you bad data then you should work out how to eliminate your dependency on that data source. – Michael Kay Feb 19 '23 at 00:32
  • I understand that it is not the best solution to modify the soap response, but is it possible? Has it been done before with success? As for error handling, if I make the WebMethod throws an exception of type WebServiceException I can catch it. But still, I would like to know if there is a complete solution. – Olivetz Feb 19 '23 at 00:46
  • @MichaelKay I can´t eliminate the dependency on the data source because it is a very important national entity for insurance companies in my country. There has to be a way. – Olivetz Feb 19 '23 at 01:27
  • No, there does not have to be a way to use XML tools on non-XML data. – kjhughes Feb 19 '23 at 02:45
  • @kjhughes and why can not I intercept non-XML data with another library or tools so I can get the data? – Olivetz Feb 19 '23 at 03:07
  • 1
    Of course you can use non-XML tools on non-XML data, but your question is about SOAP, an XML-based protocol. As long as you're using SOAP-based or XML-based libraries, you shouldn't expect help from those libraries for non-XML data. If you want to operate at the HTTP level, pre-process the data as text, and attempt repairs against our recommendations, you're free to do so. The most I'd help you go down that non-recommended path, however, is to offer [How to parse invalid (bad / not well-formed) XML?](https://stackoverflow.com/q/44765194/290085), ***especially option #1.*** – kjhughes Feb 19 '23 at 03:52
  • Thank you for your answer, I'll see what I can do with this information. But this question is still open for other solutions... – Olivetz Feb 19 '23 at 04:05
  • It looks like there is a start character are the beginning of the response. Best way of removing would be similar to how I would do it in c#. First use a non xml reader like StringReader to read response and then remove the first character(s). Then feed the StringReader as input into XmlReader. – jdweng Feb 19 '23 at 09:08
  • It is not really clear to me whether you call a SOAP service and get a bad response or someone calls your SOAP service and sends a bad request. For the latter you can intercept the HTTP request with a ServletFilter and manipulate the request as plain text. If you call a service not under your control you can use a low level HTTP request to call the SOAP service without any SOAP libraries. Then you get the response as plain text, can correct the error, parse the XML on your own and extract the payload.Something like SoapUI can be used to show you the low level HTTP request for the service call. – vanje Feb 19 '23 at 13:12
  • @vanje I call a external SOAP service, the problem is when I get the response there's an invalid character. Do you have an example of how to intercept it? – Olivetz Feb 19 '23 at 20:10
  • @jdwengn I tried to intercept the response but I failed. – Olivetz Feb 19 '23 at 20:11
  • If you need to handle data in a non-XML format then of course it's possible. Just don't try to use XML tools for the job. – Michael Kay Feb 20 '23 at 08:04
  • @Olivetz: Here is an example how to call a SOAP service without SOAP libraries: https://technology.amis.nl/soa/how-to-call-a-call-a-webservice-directly-from-java-without-webservice-library/ – vanje Feb 20 '23 at 10:06
  • @vanje looks nice!, I'm gonna try this approach – Olivetz Feb 20 '23 at 15:03
  • @vanje I tried it and it seems to work!!!!!!!! – Olivetz Feb 20 '23 at 16:44
  • @vanje If you want, create a formal answer and I'll mark you as the correct answer. – Olivetz Feb 20 '23 at 17:13

1 Answers1

0

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;
}
vanje
  • 10,180
  • 2
  • 31
  • 47