Hi Sean,

I'm still unable to reproduce this. What container do you use?

I use WildFly (with Undertow) with RESTEasy 3.0.17. I attach WildFly application (with end-point and exception mapper) and junit test with client part. I still see only ProcessingException:

  1. mvn package -DskipTests
  2. deploy
  3. mvn test

I see this exception:

javax.ws.rs.ProcessingException: java.lang.IllegalStateException: RESTEASY004575: Input stream was empty, there is no entity
    at org.jboss.resteasy.client.jaxrs.internal.ClientResponse.readFrom(ClientResponse.java:285)
    at org.jboss.resteasy.client.jaxrs.internal.ClientResponse.readEntity(ClientResponse.java:181)
    at org.jboss.resteasy.specimpl.BuiltResponse.readEntity(BuiltResponse.java:219)
    at org.resteasy.test.MyTest.testBuildResponse(MyTest.java:29)
    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:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
    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:498)
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
    at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Caused by: java.lang.IllegalStateException: RESTEASY004575: Input stream was empty, there is no entity
    at org.jboss.resteasy.client.jaxrs.internal.ClientResponse.readFrom(ClientResponse.java:239)
    ... 32 more


Marek

On 06/14/2016 09:08 PM, Sean Dawson wrote:

Hi Marek, thanks for the response.

So I think you're right - that in the simplest of testcases, buffering of the (null) entity is NOT attempted.

There are a few other differences that may factor in to this but once I've modified the simple version to be slightly closer to our environment, the difference on the client between this...

Exception in thread "main" javax.ws.rs.RedirectionException: HTTP 304 Not Modified
 at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.extractResult(ClientInvocation.java:172)
 at org.jboss.resteasy.client.jaxrs.internal.proxy.extractors.BodyEntityExtractor.extractEntity(BodyEntityExtractor.java:60)
 at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invoke(ClientInvoker.java:104)
 at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy.invoke(ClientProxy.java:76)
Disconnected from the target VM, address: '127.0.0.1:64538', transport: 'socket'
 at com.sun.proxy.$Proxy18.download(Unknown Source)
 at Client.main(Client.java:29)
Process finished with exit code 1

And this...

Exception in thread "main" java.lang.NullPointerException
 at org.jboss.resteasy.util.ReadFromStream.readFromStream(ReadFromStream.java:30)
 at org.jboss.resteasy.client.jaxrs.internal.ClientResponse.bufferEntity(ClientResponse.java:307)
 at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.extractResult(ClientInvocation.java:155)
 at org.jboss.resteasy.client.jaxrs.internal.proxy.extractors.BodyEntityExtractor.extractEntity(BodyEntityExtractor.java:60)
 at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invoke(ClientInvoker.java:104)
 at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy.invoke(ClientProxy.java:76)
 at com.sun.proxy.$Proxy18.download(Unknown Source)
 at Client.main(Client.java:29)
Process finished with exit code 1

Is one line registering this exception mapper provider on the server (ie. adding it for the second run)...

@Provider
public class MyExceptionMapper implements ExceptionMapper<WebApplicationException>
{
    @Override
    public Response toResponse(WebApplicationException wae)
    {
        int status = wae.getResponse().getStatus();
        Response.ResponseBuilder responseBuilder = Response.status(status);
        return responseBuilder.entity(wae.toString()).build();
    }
}
In both cases the status code is 304.  My actual exception mapper(s) are more complicated than this - setting media types, etc - but in this simple version, the above shows our issue.  What more/else should I be doing instead?



On Tue, Jun 14, 2016 at 4:44 AM, Marek Kopecky <mkopecky@redhat.com> wrote:

Hi.

The mailing-list on sourceforge (resteasy-developers@lists.sourceforge.net) has been deprecated. Forwarding to correct mailing list ( resteasy-dev@lists.jboss.org ).

Yes, "A 304 response cannot contain a message-body", see https://tools.ietf.org/html/rfc7232#section-4.1

Sean, can you sent example of your end-point and client part? I tried to use this endpoint and client. It works as I expected. Any NPE is thrown:

@GET
@Path("nothing")
@Produces("application/octet-stream")
public InputStream nothing() {
    if (true) {
        throw new WebApplicationException(304);
    }
    return new ByteArrayInputStream("hello".getBytes());
}

-----------------------------------------------------------------------------------

Response response = client.target(generateURL("/nothing")).request().get();
int code = response.getStatus();
if (code == 200) {
    InputStream is = response.readEntity(InputStream.class);
    Assert.assertEquals("hello", TestUtil.readString(is));
}
if (code == 304) {
    try {
        response.readEntity(InputStream.class);
        Assert.fail("ProcessingException was not thrown");
    } catch (ProcessingException e) {
        // expected exception
    }
}
response.close();
But I found some performance issue with 304. If I use this end-point:
@GET
@Path("nothing")
public Response nothing()
{
   return Response.status(304).entity("test").build();
}
In WildFly, body is erased in Undertow (AFAIK), but RESTEasy could do this too. Check for 304 can be implemented here: https://github.com/resteasy/Resteasy/blob/master/resteasy-jaxrs/src/main/java/org/jboss/resteasy/core/ServerResponseWriter.java#L50 Now, interceptors are applied to these kinds of responses. This is not necessary and it may not be optimal for performance. Alessio, Ron, WDYT? Marek -------- Forwarded Message --------
Subject: [Resteasy-developers] Proper handling of NotModified/304
Date: Fri, 10 Jun 2016 10:50:03 -0400
From: Sean Dawson <sean.dawson2014@gmail.com>
To: resteasy-devel. <resteasy-developers@lists.sourceforge.net>
I posted this on users but I'm thinking it's a RestEasy bug at this point.
The code seems to buffer the entity and then throw a processing exception if the status is bad.
In the case of 304, no body is provided (and this seems to be correct according to the standard).  I have found no way server side to return anything but null as the entity.  So attempting to buffer it on a 304 just seems plain incorrect (and results in an NPE).
Am I missing something?
Setting the custom header on the response does work - but I'm not sure that'll make it back to the client when it passes through servers that usually strip those out.