[
https://issues.apache.org/jira/browse/CXF-6463?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14587924#comment-14587924
]
Seth Leger commented on CXF-6463:
---------------------------------
I agree that it is a Spring bug. The Servlet spec Javadoc doesn't mention that
null is a valid return value for getInputStream(). I think they might have
fixed this already in Spring 4.1 based on this bug:
https://jira.spring.io/browse/SPR-11764
I still think it would be better if CXF defensively coded against this behavior
and returned a more meaningful stack trace with an error that said something
like "Null ServletInputStream on HttpServletRequest" before it gets down into
IOUtils. Anyone unit testing CXF with Spring 3.2 or 4.0 could potentially run
into this issue and based on searching for similar issues, it appears to be a
common misreading of the Servlet spec.
https://access.redhat.com/solutions/744613
> AbstractHTTPDestination.cacheInput() throws NullPointerException if
> HttpServletRequest returns null for getInputStream()
> ------------------------------------------------------------------------------------------------------------------------
>
> Key: CXF-6463
> URL: https://issues.apache.org/jira/browse/CXF-6463
> Project: CXF
> Issue Type: Bug
> Components: JAX-RS
> Affects Versions: 3.1.1
> Reporter: Seth Leger
>
> I am writing a unit test executing inside Spring 4.0's @WebApplicationContext
> unit test framework that invokes CXFServlet. Spring's framework provides a
> MockHttpServletRequest object that you can construct as input to a servlet
> request/response dispatch call.
> If the incoming message body of the MockHttpServletRequest is empty, then
> when you call getInputStream() on it, MockHttpServletRequest will return null
> instead of returning a ServletInputStream that contains no data.
> The code under the CXFServlet doesn't appear to like this behavior and
> crashes with a pretty mysterious stack trace:
> {noformat}
> 2015-06-15 17:29:39,399 DEBUG [main]
> org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleMessage on
> interceptor org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor@3118ed2c
> 2015-06-15 17:29:39,400 DEBUG [main]
> org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor - Response content type
> is: text/plain
> 2015-06-15 17:29:39,400 DEBUG [main]
> org.apache.cxf.ws.addressing.ContextUtils - retrieving MAPs from context
> property javax.xml.ws.addressing.context.inbound
> 2015-06-15 17:29:39,400 DEBUG [main]
> org.apache.cxf.ws.addressing.ContextUtils - WS-Addressing - failed to
> retrieve Message Addressing Properties from context
> 2015-06-15 17:29:39,401 ERROR [main] org.apache.cxf.jaxrs.utils.JAXRSUtils -
> Problem with writing the data, class java.lang.String, ContentType: text/plain
> 2015-06-15 17:29:39,402 DEBUG [main]
> org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleFault on
> interceptor org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor@3118ed2c
> 2015-06-15 17:29:39,402 DEBUG [main]
> org.apache.cxf.phase.PhaseInterceptorChain - Invoking handleFault on
> interceptor org.apache.cxf.interceptor.MessageSenderInterceptor@1b6824c1
> 2015-06-15 17:29:39,403 WARN [main]
> org.apache.cxf.phase.PhaseInterceptorChain - Interceptor for
> {http://rest.web.opennms.org/}AcknowledgmentRestService has thrown exception,
> unwinding now
> org.apache.cxf.interceptor.Fault
> at
> org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.handleWriteException(JAXRSOutInterceptor.java:371)
> at
> org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.serializeMessage(JAXRSOutInterceptor.java:272)
> at
> org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.processResponse(JAXRSOutInterceptor.java:118)
> at
> org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.handleMessage(JAXRSOutInterceptor.java:81)
> at
> org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
> at
> org.apache.cxf.interceptor.OutgoingChainInterceptor.handleMessage(OutgoingChainInterceptor.java:83)
> at
> org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
> at
> org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
> at
> org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:251)
> at
> org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234)
> at
> org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208)
> at
> org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160)
> at
> org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:171)
> at
> org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:293)
> at
> org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:217)
> at javax.servlet.http.HttpServlet.service(HttpServlet.java:735)
> at
> org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:268)
> at
> org.opennms.core.test.rest.AbstractSpringJerseyRestTestCase$1.doFilter(AbstractSpringJerseyRestTestCase.java:240)
> at
> org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:232)
> at
> org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
> at
> org.opennms.core.test.rest.AbstractSpringJerseyRestTestCase.dispatch(AbstractSpringJerseyRestTestCase.java:244)
> at
> org.opennms.core.test.rest.AbstractSpringJerseyRestTestCase.sendRequest(AbstractSpringJerseyRestTestCase.java:482)
> at
> org.opennms.core.test.rest.AbstractSpringJerseyRestTestCase.sendRequest(AbstractSpringJerseyRestTestCase.java:477)
> at
> org.opennms.core.test.rest.AbstractSpringJerseyRestTestCase.sendRequest(AbstractSpringJerseyRestTestCase.java:473)
> at
> org.opennms.web.rest.MinionRestServiceTest.testGetProperty(MinionRestServiceTest.java:116)
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
> at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> at java.lang.reflect.Method.invoke(Method.java:497)
> at
> org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
> at
> org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
> at
> org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
> at
> org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
> at
> org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
> at
> org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
> at
> org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
> at
> org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
> at
> org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
> at
> org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:233)
> at
> org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:87)
> at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
> at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
> at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
> at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
> at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
> at
> org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
> at
> org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
> at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
> at
> org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:176)
> at
> org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
> at
> org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
> at
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
> at
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
> at
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
> at
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
> Caused by: java.lang.NullPointerException
> at org.apache.cxf.helpers.IOUtils.copy(IOUtils.java:182)
> at org.apache.cxf.helpers.IOUtils.copy(IOUtils.java:141)
> at
> org.apache.cxf.io.DelegatingInputStream.cacheInput(DelegatingInputStream.java:54)
> at
> org.apache.cxf.transport.http.AbstractHTTPDestination$1.cacheInput(AbstractHTTPDestination.java:308)
> at
> org.apache.cxf.transport.http.AbstractHTTPDestination.cacheInput(AbstractHTTPDestination.java:582)
> at
> org.apache.cxf.transport.http.AbstractHTTPDestination.flushHeaders(AbstractHTTPDestination.java:604)
> at
> org.apache.cxf.transport.http.AbstractHTTPDestination.flushHeaders(AbstractHTTPDestination.java:597)
> at
> org.apache.cxf.transport.http.AbstractHTTPDestination$WrappedOutputStream.onFirstWrite(AbstractHTTPDestination.java:782)
> at
> org.apache.cxf.io.AbstractWrappedOutputStream.write(AbstractWrappedOutputStream.java:47)
> at
> org.apache.cxf.io.AbstractWrappedOutputStream.write(AbstractWrappedOutputStream.java:60)
> at
> org.apache.cxf.jaxrs.provider.StringTextProvider.writeTo(StringTextProvider.java:72)
> at
> org.apache.cxf.jaxrs.provider.StringTextProvider.writeTo(StringTextProvider.java:35)
> at
> org.apache.cxf.jaxrs.utils.JAXRSUtils.writeMessageBody(JAXRSUtils.java:1375)
> at
> org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.serializeMessage(JAXRSOutInterceptor.java:250)
> ... 53 more
> {noformat}
> If I subclass MockHttpServletRequest and have it return an empty
> ServletInputStream instead of null, then CXF works without throwing the NPE.
> Just to be defensive, you might want to check for null return values from
> HttpServletRequest.getInputStream(). It seems like several people have run
> into issues with this, like this mailing list post:
> http://mail-archives.apache.org/mod_mbox/cxf-users/201104.mbox/%[email protected]%3E
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)