javaweb-servicestomcatsoapsaaj

Why can't com.sun.xml.internal.messaging.saaj.soap.impl.TextImpl be cast to javax.xml.soap.SOAPBodyElement


Update

I have found something that may be related, removing whitespace from the response. But what's the best way to do that?

Original Post

I am in the process of moving a Tomcat 6 (using Java 6) server to Tomcat 8.5 (using Java 8u111). One of the jsp's is giving me a problem on the new server. It sends a SOAP request and processes the response. I get the following error out of it

Error : com.sun.xml.internal.messaging.saaj.soap.impl.TextImpl cannot be cast to javax.xml.soap.SOAPBodyElement

when executing line 245

SOAPBodyElement sbeResponseRoot = (SOAPBodyElement) iterRoot.next();

This is the SOAP response it is trying to process.

<?xml version="1.0" encoding="UTF-8" ?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:WS_TestResponse xmlns:ns1="LLX_Service">
    <outResultCode xsi:type="xsd:int">-1</outResultCode>
    <outResultMsg xsi:type="xsd:string">Invalid ID Value, record not found</outResultMsg>
    <outResultData xsi:type="xsd:string">IsTermed=No</outResultData>
</ns1:WS_TestResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Full stack trace follows:

org.apache.jsp.util.ws.ws_test_id_jsp._jspService(ws_test_id_jsp.java:245)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:443)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:385)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:329)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474)
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624)
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783)
org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:789)
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1437)
org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
java.lang.Thread.run(Unknown Source)

And a copy of the code.

/*
 * Generated by the Jasper component of Apache Tomcat
 * Version: Apache Tomcat/8.5.9
 * Generated at: 2016-12-28 02:33:46 UTC
 * Note: The last modified time of this file was set to
 *       the last modified time of the source file after
 *       generation to assist with modification tracking.
 */
package org.apache.jsp.util.ws;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import javax.xml.soap.*;
import java.net.*;
import java.util.*;
import java.sql.*;
import org.w3c.dom.*;

public final class ws_test_id_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent,
                 org.apache.jasper.runtime.JspSourceImports {

  private static final javax.servlet.jsp.JspFactory _jspxFactory =
          javax.servlet.jsp.JspFactory.getDefaultFactory();

  private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;

  static {
    _jspx_dependants = new java.util.HashMap<java.lang.String,java.lang.Long>(4);
    _jspx_dependants.put("/util/inc_data_load.jsp", Long.valueOf(1348785010000L));
    _jspx_dependants.put("/util/inc_ws_data_test_emp.jsp", Long.valueOf(1482885343175L));
    _jspx_dependants.put("/util/inc_ws_base.jsp", Long.valueOf(1482885343291L));
    _jspx_dependants.put("/util/inc_ws_send.jsp", Long.valueOf(1482892420777L));
  }

  private static final java.util.Set<java.lang.String> _jspx_imports_packages;

  private static final java.util.Set<java.lang.String> _jspx_imports_classes;

  static {
    _jspx_imports_packages = new java.util.HashSet<>();
    _jspx_imports_packages.add("java.sql");
    _jspx_imports_packages.add("javax.servlet");
    _jspx_imports_packages.add("javax.xml.soap");
    _jspx_imports_packages.add("java.util");
    _jspx_imports_packages.add("java.net");
    _jspx_imports_packages.add("org.w3c.dom");
    _jspx_imports_packages.add("javax.servlet.http");
    _jspx_imports_packages.add("javax.servlet.jsp");
    _jspx_imports_classes = null;
  }

  private volatile javax.el.ExpressionFactory _el_expressionfactory;
  private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;

  public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
    return _jspx_dependants;
  }

  public java.util.Set<java.lang.String> getPackageImports() {
    return _jspx_imports_packages;
  }

  public java.util.Set<java.lang.String> getClassImports() {
    return _jspx_imports_classes;
  }

  public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
    if (_el_expressionfactory == null) {
      synchronized (this) {
        if (_el_expressionfactory == null) {
          _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
        }
      }
    }
    return _el_expressionfactory;
  }

  public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
    if (_jsp_instancemanager == null) {
      synchronized (this) {
        if (_jsp_instancemanager == null) {
          _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
        }
      }
    }
    return _jsp_instancemanager;
  }

  public void _jspInit() {
  }

  public void _jspDestroy() {
  }

  public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
      throws java.io.IOException, javax.servlet.ServletException {

    final java.lang.String _jspx_method = request.getMethod();
    if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
      response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");
      return;
    }

    final javax.servlet.jsp.PageContext pageContext;
    javax.servlet.http.HttpSession session = null;
    final javax.servlet.ServletContext application;
    final javax.servlet.ServletConfig config;
    javax.servlet.jsp.JspWriter out = null;
    final java.lang.Object page = this;
    javax.servlet.jsp.JspWriter _jspx_out = null;
    javax.servlet.jsp.PageContext _jspx_page_context = null;


    try {
      response.setContentType("text/html; charset=utf-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
                "", true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write('\r');
      out.write('\n');

    // Build XML and pass it all to the web service.  Trap any errors in strStatus.
    String strStatus = "";
    String strServiceCallName = "WS_Tester";
    String strServiceResultMsg = "";                
    Vector vecServiceResultArray = new Vector();    
    int intServiceResultCode = -42;             
    int intServiceProgressMarker = 0;
    boolean boolOK = false;
    boolean boolDebugL9On = false;

    // Always debug on the test server.
    boolDebugL9On = ((request.getServerName().trim().toLowerCase().compareTo("testserver") == 0) || boolDebugL9On);

    try {


    // Test data for push.
    String strID = "111223499";
    String strEmpNum = "890168";
    String strLastName = "Tester12";
    String strFirstName = "Sammy";
    String strMiddleName = "P";
    String strMaidenName = "";
    String strDOB = "07/05/1988";
    String strHireDate = "09/21/2012";
    String strTitle = "VP of Testing";
    String strAddressLine1 = "400 W. Jones Ave.";
    String strAddressLine2 = "Hancock Building, Apt. C4";
    String strCity = "myTown";
    String strState = "WA";
    String strPostalCode = "99999";
    String strGLocNum = "12038"; 
    String strOccGrp = "Facility"; 


    // Init the factories.
    SOAPConnectionFactory scfFactory = SOAPConnectionFactory.newInstance();
    SOAPFactory sfFactory = SOAPFactory.newInstance();
    MessageFactory mfFactory = MessageFactory.newInstance();

    // Create the SOAP Connection.
    SOAPConnection scTunnel = scfFactory.createConnection();

    // Build the SOAP request message.
    SOAPMessage smRequest = mfFactory.createMessage();

    // Set the extra envelope attributes.
    SOAPEnvelope seEnvelope = smRequest.getSOAPPart().getEnvelope();;

    seEnvelope.setAttribute("xmlns:SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/");
    seEnvelope.setAttribute("xmlns:SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/");
    seEnvelope.setAttribute("xmlns:http", "http://schemas.xmlsoap.org/wsdl/http/");
    seEnvelope.setAttribute("xmlns:soap", "http://schemas.xmlsoap.org/wsdl/soap/");
    seEnvelope.setAttribute("xmlns:tns", "LLX_Service");

    // Remove the SOAP message header, it is not needed in this case.
    SOAPHeader shRequestHeader = smRequest.getSOAPHeader();
    shRequestHeader.detachNode();

    // Build the SOAP body element CheckProspect.
    SOAPBody sbRequestBody = smRequest.getSOAPBody();
    javax.xml.soap.Name nameRequestName = sfFactory.createName(strServiceCallName, "mns", "LLX_Service");
    SOAPBodyElement sbeRequestElement = sbRequestBody.addBodyElement(nameRequestName);

    // Add all child elements to the WS action element.
    SOAPElement seComKey = sbeRequestElement.addChildElement("key");
    seComKey.addTextNode("user");

    SOAPElement seComPW = sbeRequestElement.addChildElement("pw");
    seComPW.addTextNode("pass");

    SOAPElement seEmpID = sbeRequestElement.addChildElement("id");
    seEmpID.addTextNode("myid="+strID);

    if (boolDebugL9On) {
        // Debug code, writes xml to the log file.
        System.out.println("");
        smRequest.writeTo(System.out);
        System.out.println("");
    } // End if (boolDebugL9On)

    URL urlWebService = new URL ("https://www.xxxxxxxxxxxx.com/xxxxxxxx/");
    // Send the SOAP request message and get back the SOAP response message.
    SOAPMessage smResponse = scTunnel.call(smRequest, urlWebService);

    scTunnel.close();

    if (boolDebugL9On) {
        // Debug code, writes xml to the log file.
        System.out.println("");
        smResponse.writeTo(System.out);
        System.out.println("");
    } // End if (boolDebugL9On)

    strServiceResultMsg = "Processing call.";
    vecServiceResultArray = new Vector();
    intServiceResultCode = -10000;

    // Pull out the SOAP response body.
    SOAPBody sbResponseBody = smResponse.getSOAPBody();

    // Check for SOAP faults.
    if (sbResponseBody.hasFault()) {
        intServiceProgressMarker = 101; // Tracking information.
        SOAPFault newFault = sbResponseBody.getFault();
        strStatus = "SOAP FAULT:<br>";
        strStatus += "<br>code = " + newFault.getFaultCodeAsName();
        strStatus += "<br>message = " + newFault.getFaultString();
        strStatus += "<br>actor = " + newFault.getFaultActor()+"<br>";
        strServiceResultMsg = "WS call returned a fault.";
        intServiceResultCode = -10001;
        boolOK = false;
    } else {
        // Pull the response results element out of the SOAP response body.
        java.util.Iterator iterRoot = sbResponseBody.getChildElements();
        SOAPBodyElement sbeResponseRoot = (SOAPBodyElement) iterRoot.next();
        Iterator iterElement = sbeResponseRoot.getChildElements();

        strStatus = "SOAP Response:<br>";
        do {
            //org.apache.axis.message.MessageElement meResponseElement = (org.apache.axis.message.MessageElement) iterElement.next();
            SOAPElement meResponseElement = (SOAPElement) iterElement.next();
            String strElementName = meResponseElement.getLocalName();
            String strElementValue = ((meResponseElement.getValue() == null) ? meResponseElement.toString() : meResponseElement.getValue());
            if (strElementName.compareTo("outResultCode") == 0) {
                // Check for success or failure.
                intServiceResultCode = Integer.valueOf(strElementValue).intValue();
                boolOK = (intServiceResultCode >= 0);
                intServiceProgressMarker = (boolOK) ? 1 : 100; // Tracking information.
                strStatus += "Response code came back as *" + strElementValue + "*<br>";
            } else {
                if (strElementName.compareTo("outResultMsg") == 0) {
                    strServiceResultMsg = strElementValue;
                    strStatus += "Response message came back as *" + strElementValue + "*<br>";
                } else {
                    if (strElementName.compareTo("outResultData") == 0) {
                        strServiceResultMsg = strElementValue;
                        strStatus += "Response data came back as *" + strElementValue + "*<br>";
                    } else { 
                        if (strElementName.compareTo("outData") == 0) {
                            strStatus += "Response data array came back : *" + strElementValue + "*<br>";
                            // Check for a data array.
                            if (iterRoot.hasNext()) {
                                // Load up vecServiceResultArray for later use.
                                SOAPBodyElement sbeResponseDataArray = (SOAPBodyElement) iterRoot.next();
                                java.util.Iterator iterDataArray = sbeResponseDataArray.getChildElements();
                                while (iterDataArray.hasNext()) {
                                    //org.apache.axis.message.MessageElement meDataElement = (org.apache.axis.message.MessageElement) iterDataArray.next();
                                    SOAPElement meDataElement = (SOAPElement) iterDataArray.next();
                                    String strDataName = meDataElement.getLocalName();
                                    String strDataValue = ((meDataElement.getValue() == null) ? meDataElement.toString() : meDataElement.getValue());
                                    Vector vecRow = new Vector();
                                    vecRow.add(strDataName);
                                    vecRow.add(strDataValue);
                                    vecServiceResultArray.add(vecRow);
                                } // End while (iterDataArray.hasNext())
                            } // End if (iterRoot.hasNext())
                        } else {
                            strStatus += "Unknown response element returned, it is called *"+strElementName+"* and holds *" + strElementValue + "*<br>";
                        } // End if (strElementName.compareTo("outData") == 0)
                    } // End if (strElementName.compareTo("outResultData") == 0)
                } // End if (strElementName.compareTo("outResultMsg") == 0)
            } // End if (strElementName.compareTo("outResultCode") == 0)
        } while (iterElement.hasNext());
    } // End if (sbResponseBody.hasFault())



    } catch(Exception e) {
        intServiceProgressMarker = 102; // Tracking information.
        strStatus = "Error : "+((e.getMessage() != null) ? e.getMessage() : e.toString());
        strStatus += "<br>";
        boolOK = false;

        StackTraceElement[] aryStackTrace = e.getStackTrace();
        for (int intElement = 0; intElement < aryStackTrace.length; intElement++)
        {
            strStatus += aryStackTrace[intElement].toString();
            strStatus += "<br>";
        }
    } // End try


      out.write("\r\n");
      out.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\r\n");
      out.write("<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n");
      out.write("\t<head>\r\n");
      out.write("\t\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\r\n");
      out.write("\t\t<title>Test Web Service</title>\r\n");
      out.write("\t</head>\r\n");
      out.write("\t\r\n");
      out.write("\t<body>\r\n");
      out.write("\t\t");
      out.print(strStatus);
      out.write("<br /><br />\r\n");
      out.write("\t\t");

        for (int intRow = 0; intRow < vecServiceResultArray.size(); intRow++) {
            Vector vecRow = (Vector) vecServiceResultArray.elementAt(intRow);

      out.write("<div><span>");
      out.print(vecRow.elementAt(0));
      out.write("</span>&nbsp;|&nbsp;<span>");
      out.print(vecRow.elementAt(1));
      out.write("</span></div>");

        } // End for (int intRow = 0; intRow < vecServiceResultArray.size(); intRow++)

      out.write("\r\n");
      out.write("\t</body>\r\n");
      out.write("</html>");
    } catch (java.lang.Throwable t) {
      if (!(t instanceof javax.servlet.jsp.SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try {
            if (response.isCommitted()) {
              out.flush();
            } else {
              out.clearBuffer();
            }
          } catch (java.io.IOException e) {}
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
        else throw new ServletException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
}

Any ideas on why this is happening?


Solution

  • Ok, if anyone else runs up against this here is what I found and how I fixed it. Whitespaces, like new line and carriage return and tab in the body element screwed up parsing the child elements. To strip them out I replaced the following line:

    SOAPMessage smResponse = scTunnel.call(smRequest, urlWebService);
    

    with this code snip:

    SOAPMessage smResponse2 = scTunnel.call(smRequest, urlWebService);
    
    // strip off the newlines and CR's and tabs.
    java.io.ByteArrayOutputStream baosHolder = new java.io.ByteArrayOutputStream();
    smResponse2.writeTo(baosHolder);
    String strSOAPMsg = baosHolder.toString().replaceAll("\n+","").replaceAll("\r+","").replaceAll("\t+","");
    
    SOAPMessage smResponse = mfFactory.createMessage(new MimeHeaders(), new java.io.ByteArrayInputStream(strSOAPMsg.getBytes(java.nio.charset.Charset.forName("UTF-8"))));
    

    That converted the javax.xml.soap.SOAPMessage to a string via the java.io.ByteArrayOutputStream object, replaced the offending chars, and wrapped it back up in a new SOAPMessage object that didn't have the whitespace and would parse normally.

    That turned the response from this:

    <?xml version="1.0" encoding="UTF-8" ?>
    <SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <SOAP-ENV:Body>
    <ns1:WS_TestResponse xmlns:ns1="LLX_Service">
        <outResultCode xsi:type="xsd:int">-1</outResultCode>
        <outResultMsg xsi:type="xsd:string">Invalid ID Value, record not found</outResultMsg>
        <outResultData xsi:type="xsd:string">IsTermed=No</outResultData>
    </ns1:WS_TestResponse>
    </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    

    to this:

    <?xml version="1.0" encoding="UTF-8" ?><SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><SOAP-ENV:Body><ns1:WS_TestResponse xmlns:ns1="LLX_Service"><outResultCode xsi:type="xsd:int">-1</outResultCode><outResultMsg xsi:type="xsd:string">Invalid ID Value, record not found</outResultMsg><outResultData xsi:type="xsd:string">IsTermed=No</outResultData></ns1:WS_TestResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
    

    If there is an easier way, I'd love to hear it.