eclipse-ee4j / jersey

Eclipse Jersey Project - Read our Wiki:
https://github.com/eclipse-ee4j/jersey/wiki
Other
692 stars 355 forks source link

javax.ws.rs.client.ResponseProcessingException is never thrown. #3277

Open jerseyrobot opened 8 years ago

jerseyrobot commented 8 years ago

My analysis so far is as following: AbstractRootElementJaxbProvider throws subclasses of WebApplicationException instead of an IOException: https://jersey.java.net/project-info/2.22.1/jersey/project/jersey-media-jaxb/xref/org/glassfish/jersey/jaxb/internal/AbstractRootElementJaxbProvider.html

At least in the latest version this handled somewhat in JerseyInvocation, where WebApplicationException gets catched and wrapped by a ResponseProcessingException.

https://github.com/jersey/jersey/blob/master/core-client/src/main/java/org/glassfish/jersey/client/JerseyInvocation.java#L858

This is wakwards since the nested exception provides a wrong HTTP status code (eg. "HTTP 400 Bad Request", where the request itself was succesful.

In the end the nested WebApplicationException gets unwrapped again: https://github.com/jersey/jersey/blob/master/core-client/src/main/java/org/glassfish/jersey/client/JerseyInvocation.java#L690

So I think the best thing would be if the AbstractRootElementJaxbProvider class would throw IOException.

The case of a thrown WebApplicationException should never arise when calling response.readEntity (translate method). So the catch clause should be removed and it should be made sure this case never arises (otherwise it would still be catched by the Exception catch statement).

The unwrapping of the cause of the ProcessingException in the translate method also seems wrong in some cases (e.g. when there is no cause). Why not just set the ProcessingException itself as cause?

The IllegalStateException is not handled specially while ProcessingException is. Seems inconsistent.

And last but not least the WebApplicationException should not be unwrapped in the invoke method. Again, I think WebApplicationException should never be the cause of a ProcessingException anyway.

Affected Versions

[2.22.1]

jerseyrobot commented 6 years ago
jerseyrobot commented 8 years ago

@glassfishrobot Commented Reported by puce

jerseyrobot commented 8 years ago

@glassfishrobot Commented puce said: I don't seem to have enough rights to fix the typos...

jerseyrobot commented 8 years ago

@glassfishrobot Commented puce said: OK, according to the Javadoc, the readFrom method of a MessageBodyReader may throw a WebApplicationException, which seems strange as this seems only to make sense on the server side when parsing request messages.

But the same classes are also used on client side to parse response messages, which happens after the webservice has been called (which might be successful or not) and thus readFrom method should not affect the HTTP status code in this case.

http://docs.oracle.com/javaee/7/api/javax/ws/rs/ext/MessageBodyReader.html#readFrom-java.lang.Class-java.lang.reflect.Type-java.lang.annotation.Annotation:A-javax.ws.rs.core.MediaType-javax.ws.rs.core.MultivaluedMap-java.io.InputStream-

jerseyrobot commented 8 years ago

@glassfishrobot Commented puce said: You should be able to reproduce this issue by writing a JAX-RS client which calls a GET request and tries to unmarshal the response with JAXB using: https://docs.oracle.com/javaee/7/api/javax/ws/rs/client/SyncInvoker.html#get-java.lang.Class-

and

<dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-jaxb</artifactId>
            <version>${jersey.version}</version>
        </dependency>

where the response provided by the server does contain a different content than expected -> call was successful, but unmarshalling fails -> should throw a ResponseProcessingException not a WebApplicationException

jerseyrobot commented 8 years ago

@glassfishrobot Commented puce said: The same issue also happens if you call: response.readEntity(MyJaxbClass.class)

javax.ws.rs.BadRequestException: HTTP 400 Bad Request
    at org.glassfish.jersey.jaxb.internal.AbstractRootElementJaxbProvider.readFrom(AbstractRootElementJaxbProvider.java:136)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.invokeReadFrom(ReaderInterceptorExecutor.java:256)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:235)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:155)
    at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1085)
    at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:874)
    at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:808)
    at org.glassfish.jersey.client.ClientResponse.readEntity(ClientResponse.java:326)
    at org.glassfish.jersey.client.InboundJaxrsResponse$1.call(InboundJaxrsResponse.java:115)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:419)
    at org.glassfish.jersey.client.InboundJaxrsResponse.runInScopeIfPossible(InboundJaxrsResponse.java:267)
    at org.glassfish.jersey.client.InboundJaxrsResponse.readEntity(InboundJaxrsResponse.java:112)
    at <some class>
    at <some class>
    at <some class>
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:94)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
    at java.lang.reflect.Method.invoke(Method.java:619)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at com.github.tomakehurst.wiremock.junit.WireMockStaticRule$1.evaluate(WireMockStaticRule.java:55)
    at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:110)
    at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
Caused by: javax.xml.bind.UnmarshalException
 - with linked exception:
[Exception [EclipseLink-25008] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor with default root element foo was not found in the project]
    at org.eclipse.persistence.jaxb.JAXBUnmarshaller.handleXMLMarshalException(JAXBUnmarshaller.java:1072)
    at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:326)
    at org.glassfish.jersey.jaxb.internal.XmlRootElementJaxbProvider.readFrom(XmlRootElementJaxbProvider.java:140)
    at org.glassfish.jersey.jaxb.internal.AbstractRootElementJaxbProvider.readFrom(AbstractRootElementJaxbProvider.java:134)
    ... 41 more
Caused by: Exception [EclipseLink-25008] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor with default root element foo was not found in the project
    at org.eclipse.persistence.exceptions.XMLMarshalException.noDescriptorWithMatchingRootElement(XMLMarshalException.java:162)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshallerHandler.startElement(SAXUnmarshallerHandler.java:305)
    at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source)
    at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
    at org.apache.xerces.impl.XMLNSDocumentScannerImpl$NSContentDispatcher.scanRootElementHook(Unknown Source)
    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
    at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
    at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
    at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
    at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at org.eclipse.persistence.internal.oxm.record.XMLReader.parse(XMLReader.java:243)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:401)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:654)
    at org.eclipse.persistence.internal.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:581)
    at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:323)
    ... 43 more

A ProcessException would be expected in this case.

jerseyrobot commented 8 years ago

@glassfishrobot Commented puce said: Here is the stack trace of the first case, where readEntity gets called by JerseyInvocation$Builder.get :

javax.ws.rs.BadRequestException: HTTP 400 Bad Request
    at org.glassfish.jersey.jaxb.internal.AbstractRootElementJaxbProvider.readFrom(AbstractRootElementJaxbProvider.java:136)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.invokeReadFrom(ReaderInterceptorExecutor.java:256)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:235)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:155)
    at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1085)
    at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:874)
    at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:808)
    at org.glassfish.jersey.client.ClientResponse.readEntity(ClientResponse.java:326)
    at org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:803)
    at org.glassfish.jersey.client.JerseyInvocation.access$700(JerseyInvocation.java:92)
    at org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:700)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:444)
    at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:696)
    at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:420)
    at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:316)
    at <some class>
    at <some class>
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:94)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
    at java.lang.reflect.Method.invoke(Method.java:619)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at com.github.tomakehurst.wiremock.junit.WireMockStaticRule$1.evaluate(WireMockStaticRule.java:55)
    at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:110)
    at com.intellij.junit4.JUnit4TestRunnerUtil$IgnoreIgnoredTestJUnit4ClassRunner.runChild(JUnit4TestRunnerUtil.java:341)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:94)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
    at java.lang.reflect.Method.invoke(Method.java:619)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: javax.xml.bind.UnmarshalException
 - with linked exception:
[Exception [EclipseLink-25008] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor with default root element foo was not found in the project]
    at org.eclipse.persistence.jaxb.JAXBUnmarshaller.handleXMLMarshalException(JAXBUnmarshaller.java:1072)
    at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:326)
    at org.glassfish.jersey.jaxb.internal.XmlRootElementJaxbProvider.readFrom(XmlRootElementJaxbProvider.java:140)
    at org.glassfish.jersey.jaxb.internal.AbstractRootElementJaxbProvider.readFrom(AbstractRootElementJaxbProvider.java:134)
    ... 47 more
Caused by: Exception [EclipseLink-25008] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor with default root element foo was not found in the project
    at org.eclipse.persistence.exceptions.XMLMarshalException.noDescriptorWithMatchingRootElement(XMLMarshalException.java:162)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshallerHandler.startElement(SAXUnmarshallerHandler.java:305)
    at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source)
    at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
    at org.apache.xerces.impl.XMLNSDocumentScannerImpl$NSContentDispatcher.scanRootElementHook(Unknown Source)
    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
    at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
    at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
    at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
    at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at org.eclipse.persistence.internal.oxm.record.XMLReader.parse(XMLReader.java:243)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:401)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:654)
    at org.eclipse.persistence.internal.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:581)
    at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:323)
    ... 49 more

In this case a ResponseProcessingException would be expected containing the response object with the correct status code.

jerseyrobot commented 8 years ago

@glassfishrobot Commented puce said: Related issue: #2740

jerseyrobot commented 8 years ago

@glassfishrobot Commented Issue-Links: is duplicated by JERSEY-2468

jerseyrobot commented 7 years ago

@glassfishrobot Commented This issue was imported from java.net JIRA JERSEY-3005

jerseyrobot commented 7 years ago

@zetlan Commented I've also been bitten by this issue – I had a JAXRS serialization error resulting from an unknown property that wasn't ignored. That caused an error whose stacktrace was only visible during debug. Somewhere in the processResponse() logic it would be helpful if the exception is re-thrown – would have saved me a couple hours of debugging.

I see this has been open quite a while – any thoughts about timing of a fix/change?