Uploaded image for project: 'RESTEasy'
  1. RESTEasy
  2. RESTEASY-1281

Unable to find contextual data of type: javax.ws.rs.container.ResourceInfo when using ReadListener

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • Major
    • 3.0.17.Final
    • 3.0.14.Final
    • jaxrs
    • None
    • Hide

      The following test case will reproduce and the test 'testAsyncResponseReadListener' will fail. I will attach a project tgz to help.

      package bug
      
      import org.apache.commons.io.IOUtils
      import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer
      import org.jboss.resteasy.test.TestPortProvider
      import org.junit.AfterClass
      import org.junit.Assert
      import org.junit.BeforeClass
      import org.junit.Test
      
      import javax.servlet.ReadListener
      import javax.servlet.ServletInputStream
      import javax.servlet.http.HttpServletRequest
      import javax.ws.rs.ApplicationPath
      import javax.ws.rs.GET
      import javax.ws.rs.POST
      import javax.ws.rs.Path
      import javax.ws.rs.client.Client
      import javax.ws.rs.client.ClientBuilder
      import javax.ws.rs.client.Entity
      import javax.ws.rs.container.AsyncResponse
      import javax.ws.rs.container.ContainerRequestContext
      import javax.ws.rs.container.ContainerRequestFilter
      import javax.ws.rs.container.ContainerResponseContext
      import javax.ws.rs.container.ContainerResponseFilter
      import javax.ws.rs.container.ResourceInfo
      import javax.ws.rs.container.Suspended
      import javax.ws.rs.core.Application
      import javax.ws.rs.core.Context
      import javax.ws.rs.core.Response
      import javax.ws.rs.ext.Provider
      import java.lang.reflect.Method
      import java.util.concurrent.TimeUnit
      
      class RestEasyTest {
      
          private static UndertowJaxrsServer server
      
          @Provider
          public static class Filter implements ContainerRequestFilter, ContainerResponseFilter {
      
              @Context
              private ResourceInfo resourceInfo
      
              @Override
              void filter(ContainerRequestContext requestContext) throws IOException {
                  Method method = resourceInfo.resourceMethod
                  println("Got method ${method.name} on request")
              }
      
              @Override
              void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
                  Method method = resourceInfo.resourceMethod //<-- fails here when using ReadListener
                  println("Got method ${method.name} on response")
              }
          }
      
          @Path('/test')
          public static class Resource {
      
              @Context
              private HttpServletRequest request
      
              @GET
              @Path('/asyncresponse')
              public void asyncresponse(@Suspended AsyncResponse ar) {
                  ar.setTimeout(10, TimeUnit.SECONDS)
                  ar.resume('hello world')
              }
      
              @POST
              @Path("/asyncresponse/inputstream")
              public void asyncresponse_InputStream(@Suspended AsyncResponse ar) {
                  ar.setTimeout(10, TimeUnit.SECONDS)
      
                  InputStream inputStream = request.getInputStream()
                  ByteArrayOutputStream outputStream = new ByteArrayOutputStream()
      
                  IOUtils.copy(inputStream, outputStream)
      
                  inputStream.close()
                  outputStream.flush()
                  outputStream.close()
      
                  ar.resume(outputStream.toString('UTF-8'))
              }
      
      
              @POST
              @Path("/asyncresponse/bufferedreader")
              public void asyncresponse_BufferedReader(@Suspended AsyncResponse ar) {
                  ar.setTimeout(10, TimeUnit.SECONDS)
      
                  BufferedReader reader = request.getReader()
      
                  StringBuilder builder = new StringBuilder()
                  String line = null
                  while ((line = reader.readLine()) != null)
                      builder.append(line)
      
                  reader.close()
      
                  ar.resume(builder.toString())
              }
      
      
              @POST
              @Path("/asyncresponse/readlistener")
              public void asyncresponse_ReadListener(@Suspended AsyncResponse async) {
                  ServletInputStream inputStream = request.getInputStream()
                  ByteArrayOutputStream outputStream = new ByteArrayOutputStream()
      
                  inputStream.readListener = new ReadListener() {
      
                      @Override
                      public void onDataAvailable() throws IOException {
                          IOUtils.copy(inputStream, outputStream)
                      }
      
                      @Override
                      public void onAllDataRead() throws IOException {
                          inputStream.close()
                          outputStream.flush()
                          outputStream.close()
      
                          async.resume(outputStream.toString('UTF-8'))
                      }
      
                      @Override
                      public void onError(Throwable t) {
                          async.resume(t)
                      }
                  }
              }
          }
      
          @ApplicationPath("/base")
          public static class MyApp extends Application {
              @Override
              public Set<Class<?>> getClasses() {
                  Set<Class<?>> classes = new HashSet<>()
                  classes.add(Resource)
                  classes.add(Filter)
                  classes
              }
          }
      
          @BeforeClass
          public static void init() throws Exception {
              server = new UndertowJaxrsServer().start()
              server.deploy(MyApp)
          }
      
          @AfterClass
          public static void stop() throws Exception {
              server.stop()
          }
      
          @Test
          public void testAsyncResponse() {
              Client client = ClientBuilder.newClient()
              String val = client.target(TestPortProvider.generateURL('/base/test/asyncresponse')).request().get(String)
              Assert.assertEquals('hello world', val)
              client.close()
          }
      
          @Test
          public void testAsyncResponseInputStream() {
              testEndpoint('/base/test/asyncresponse/inputstream')
          }
      
          @Test
          public void testAsyncResponseBufferedReader() {
              testEndpoint('/base/test/asyncresponse/bufferedreader')
          }
      
          @Test
          public void testAsyncResponseReadListener() {
              testEndpoint('/base/test/asyncresponse/readlistener')
          }
      
          private void testEndpoint(String endpoint) {
              Client client = ClientBuilder.newClient()
              Response response = client.target(TestPortProvider.generateURL(endpoint)).request().post(Entity.entity('hello world', 'text/plain'))
              String val = response.readEntity(String)
              Assert.assertEquals('hello world', val)
              client.close()
          }
      }
      
      
      Show
      The following test case will reproduce and the test 'testAsyncResponseReadListener' will fail. I will attach a project tgz to help. package bug import org.apache.commons.io.IOUtils import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer import org.jboss.resteasy.test.TestPortProvider import org.junit.AfterClass import org.junit.Assert import org.junit.BeforeClass import org.junit.Test import javax.servlet.ReadListener import javax.servlet.ServletInputStream import javax.servlet.http.HttpServletRequest import javax.ws.rs.ApplicationPath import javax.ws.rs.GET import javax.ws.rs.POST import javax.ws.rs.Path import javax.ws.rs.client.Client import javax.ws.rs.client.ClientBuilder import javax.ws.rs.client.Entity import javax.ws.rs.container.AsyncResponse import javax.ws.rs.container.ContainerRequestContext import javax.ws.rs.container.ContainerRequestFilter import javax.ws.rs.container.ContainerResponseContext import javax.ws.rs.container.ContainerResponseFilter import javax.ws.rs.container.ResourceInfo import javax.ws.rs.container.Suspended import javax.ws.rs.core.Application import javax.ws.rs.core.Context import javax.ws.rs.core.Response import javax.ws.rs.ext.Provider import java.lang.reflect.Method import java.util.concurrent.TimeUnit class RestEasyTest { private static UndertowJaxrsServer server @Provider public static class Filter implements ContainerRequestFilter, ContainerResponseFilter { @Context private ResourceInfo resourceInfo @Override void filter(ContainerRequestContext requestContext) throws IOException { Method method = resourceInfo.resourceMethod println( "Got method ${method.name} on request" ) } @Override void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException { Method method = resourceInfo.resourceMethod //<-- fails here when using ReadListener println( "Got method ${method.name} on response" ) } } @Path( '/test' ) public static class Resource { @Context private HttpServletRequest request @GET @Path( '/asyncresponse' ) public void asyncresponse(@Suspended AsyncResponse ar) { ar.setTimeout(10, TimeUnit.SECONDS) ar.resume( 'hello world' ) } @POST @Path( "/asyncresponse/inputstream" ) public void asyncresponse_InputStream(@Suspended AsyncResponse ar) { ar.setTimeout(10, TimeUnit.SECONDS) InputStream inputStream = request.getInputStream() ByteArrayOutputStream outputStream = new ByteArrayOutputStream() IOUtils.copy(inputStream, outputStream) inputStream.close() outputStream.flush() outputStream.close() ar.resume(outputStream.toString( 'UTF-8' )) } @POST @Path( "/asyncresponse/bufferedreader" ) public void asyncresponse_BufferedReader(@Suspended AsyncResponse ar) { ar.setTimeout(10, TimeUnit.SECONDS) BufferedReader reader = request.getReader() StringBuilder builder = new StringBuilder() String line = null while ((line = reader.readLine()) != null ) builder.append(line) reader.close() ar.resume(builder.toString()) } @POST @Path( "/asyncresponse/readlistener" ) public void asyncresponse_ReadListener(@Suspended AsyncResponse async) { ServletInputStream inputStream = request.getInputStream() ByteArrayOutputStream outputStream = new ByteArrayOutputStream() inputStream.readListener = new ReadListener() { @Override public void onDataAvailable() throws IOException { IOUtils.copy(inputStream, outputStream) } @Override public void onAllDataRead() throws IOException { inputStream.close() outputStream.flush() outputStream.close() async.resume(outputStream.toString( 'UTF-8' )) } @Override public void onError(Throwable t) { async.resume(t) } } } } @ApplicationPath( "/base" ) public static class MyApp extends Application { @Override public Set< Class <?>> getClasses() { Set< Class <?>> classes = new HashSet<>() classes.add(Resource) classes.add(Filter) classes } } @BeforeClass public static void init() throws Exception { server = new UndertowJaxrsServer().start() server.deploy(MyApp) } @AfterClass public static void stop() throws Exception { server.stop() } @Test public void testAsyncResponse() { Client client = ClientBuilder.newClient() String val = client.target(TestPortProvider.generateURL( '/base/test/asyncresponse' )).request().get( String ) Assert.assertEquals( 'hello world' , val) client.close() } @Test public void testAsyncResponseInputStream() { testEndpoint( '/base/test/asyncresponse/inputstream' ) } @Test public void testAsyncResponseBufferedReader() { testEndpoint( '/base/test/asyncresponse/bufferedreader' ) } @Test public void testAsyncResponseReadListener() { testEndpoint( '/base/test/asyncresponse/readlistener' ) } private void testEndpoint( String endpoint) { Client client = ClientBuilder.newClient() Response response = client.target(TestPortProvider.generateURL(endpoint)).request().post(Entity.entity( 'hello world' , 'text/plain' )) String val = response.readEntity( String ) Assert.assertEquals( 'hello world' , val) client.close() } }
    • Hide

      The workaround I'm currently using is to add the Method from ResourceInfo to the request attributes on inbound.

      Show
      The workaround I'm currently using is to add the Method from ResourceInfo to the request attributes on inbound.

    Description

      I have a filter that depends on ResourceInfo from the context.

          @Provider
          public static class Filter implements ContainerRequestFilter, ContainerResponseFilter {
      
              @Context
              private ResourceInfo resourceInfo
      
              @Override
              void filter(ContainerRequestContext requestContext) throws IOException {
                  Method method = resourceInfo.resourceMethod
                  println("Got method ${method.name} on request")
              }
      
              @Override
              void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
                  Method method = resourceInfo.resourceMethod //<-- fails here when using ReadListener
                  println("Got method ${method.name} on response")
              }
          }
      

      The filter works in most cases. However, when using a ReadListener with AsyncResponse as such:

              @POST
              @Path("/asyncresponse/readlistener")
              public void asyncresponse_ReadListener(@Suspended AsyncResponse async) {
                  ServletInputStream inputStream = request.getInputStream()
                  ByteArrayOutputStream outputStream = new ByteArrayOutputStream()
      
                  inputStream.readListener = new ReadListener() {
      
                      @Override
                      public void onDataAvailable() throws IOException {
                          IOUtils.copy(inputStream, outputStream)
                      }
      
                      @Override
                      public void onAllDataRead() throws IOException {
                          inputStream.close()
                          outputStream.flush()
                          outputStream.close()
      
                          async.resume(outputStream.toString('UTF-8'))
                      }
      
                      @Override
                      public void onError(Throwable t) {
                          async.resume(t)
                      }
                  }
              }
          }
      

      I get the following exception on the outbound path:

      ERROR: RESTEASY002005: Failed executing POST /test/asyncresponse/readlistener
      org.jboss.resteasy.spi.LoggableFailure: RESTEASY003880: Unable to find contextual data of type: javax.ws.rs.container.ResourceInfo
      	at org.jboss.resteasy.core.ContextParameterInjector$GenericDelegatingProxy.invoke(ContextParameterInjector.java:55)
      	at com.sun.proxy.$Proxy32.getResourceMethod(Unknown Source)
      	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.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
      	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
      	at org.codehaus.groovy.runtime.metaclass.MethodMetaProperty$GetBeanMethodMetaProperty.getProperty(MethodMetaProperty.java:76)
      	at org.codehaus.groovy.runtime.callsite.GetEffectivePojoPropertySite.getProperty(GetEffectivePojoPropertySite.java:64)
      	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:296)
      	at bug.RestEasyTest$Filter.filter(RestEasyTest.groovy:53)
      

      Attachments

        1. filterbug.tgz
          105 kB
        2. project.tgz
          2 kB

        Issue Links

          Activity

            People

              rsigal@redhat.com Ronald Sigal
              enigma1510 Oliver Johansson (Inactive)
              Votes:
              1 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: