JBE created CXF-5231:
------------------------

             Summary: NoSuchElementException in ClientFaultConverter when stack 
trace message contains line breaks
                 Key: CXF-5231
                 URL: https://issues.apache.org/jira/browse/CXF-5231
             Project: CXF
          Issue Type: Bug
    Affects Versions: 2.7.6, 2.7.3
            Reporter: JBE


On server side, I have enabled those two flags in order to be able to retrieve 
the full exception in client :
{code}
Message.FAULT_STACKTRACE_ENABLED -> true
Message.EXCEPTION_MESSAGE_CAUSE_ENABLED -> true
{code}

The problem is that one of the exception message contains a line break "\n" 
character. Thus when the exception is thrown, here is what I have on client 
side with version 2.7.6 :

{code}
java.util.NoSuchElementException
        at java.util.StringTokenizer.nextToken(StringTokenizer.java:349)
        at 
org.apache.cxf.interceptor.ClientFaultConverter.parseStackTrackLine(ClientFaultConverter.java:288)
        at 
org.apache.cxf.interceptor.ClientFaultConverter.getCause(ClientFaultConverter.java:279)
        at 
org.apache.cxf.interceptor.ClientFaultConverter.setStackTrace(ClientFaultConverter.java:247)
        at 
org.apache.cxf.interceptor.ClientFaultConverter.handleMessage(ClientFaultConverter.java:80)
        at 
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:271)
        at 
org.apache.cxf.interceptor.AbstractFaultChainInitiatorObserver.onMessage(AbstractFaultChainInitiatorObserver.java:113)
        at 
org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor.handleMessage(CheckFaultInterceptor.java:69)
        at 
org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor.handleMessage(CheckFaultInterceptor.java:34)
        at 
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:271)
        at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:811)
        at 
org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1590)
        at 
org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1486)
        at 
org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1305)
        at 
org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
        at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:623)
        at 
org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
        at 
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:271)
        at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:541)
        at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:474)
        at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:377)
        at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:330)
        at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
        at 
org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:134)
        at com.sun.proxy.$Proxy71.execute(Unknown Source)
        at com.mycompany.client.WebServiceClient.main(WebServiceClient.java:111)

Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: Fault string, 
and possibly fault code, not set
        at 
org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:156)
        at com.sun.proxy.$Proxy71.execute(Unknown Source)
        at com.mycompany.client.WebServiceClient.main(WebServiceClient.java:111)
Caused by: java.util.NoSuchElementException
        at java.util.StringTokenizer.nextToken(StringTokenizer.java:349)
        at 
org.apache.cxf.interceptor.ClientFaultConverter.parseStackTrackLine(ClientFaultConverter.java:288)
        at 
org.apache.cxf.interceptor.ClientFaultConverter.getCause(ClientFaultConverter.java:279)
        at 
org.apache.cxf.interceptor.ClientFaultConverter.setStackTrace(ClientFaultConverter.java:247)
        at 
org.apache.cxf.interceptor.ClientFaultConverter.handleMessage(ClientFaultConverter.java:80)
        at 
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:271)
        at 
org.apache.cxf.interceptor.AbstractFaultChainInitiatorObserver.onMessage(AbstractFaultChainInitiatorObserver.java:113)
        at 
org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor.handleMessage(CheckFaultInterceptor.java:69)
        at 
org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor.handleMessage(CheckFaultInterceptor.java:34)
        at 
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:271)
        at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:811)
        at 
org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1590)
        at 
org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1486)
        at 
org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1305)
        at 
org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
        at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:623)
        at 
org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
        at 
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:271)
        at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:541)
        at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:474)
        at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:377)
        at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:330)
        at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
        at 
org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:134)
        ... 2 more
{code}

After debugging, I can see that in the getCause method of ClientFaultConverter, 
you are using a StringTokenizer to iterate through different lines.
{quote}
StringTokenizer st = new StringTokenizer(ss, "\n");
{quote}

When it comes to the exception message, we have this kind of string :

{quote}
Caused by: beginning of the message
end of the message
first line of stack trace
{quote}

Thus this piece of code:
{code}
private Throwable getCause(StringTokenizer st, String firstLine) {
        // The actual exception class of the cause might be unavailable at the
        // client -> use a standard throwable to represent the cause.
        Throwable res = new 
Throwable(firstLine.substring(firstLine.indexOf(":") + 2));
        List<StackTraceElement> stackTraceList = new 
ArrayList<StackTraceElement>();
        while (st.hasMoreTokens()) {
            String oneLine = st.nextToken();
            if (oneLine.startsWith("Caused by:")) {
                Throwable nestedCause = getCause(st, oneLine);
                res.initCause(nestedCause);
                break;
            }
            stackTraceList.add(parseStackTrackLine(oneLine));
        }
        StackTraceElement[] stackTraceElement = new 
StackTraceElement[stackTraceList.size()];
        res.setStackTrace(stackTraceList.toArray(stackTraceElement));
        return res;
    }
{code}

will result in calling "parseStackTrackLine" on element "end of the message" 
which causes the exception.

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira

Reply via email to