0

I am trying to migrate a long running REST API server from JBoss 7.1.1 to Wildfly. The application is deploying fine and works for the most part. However my security interceptor loads the servlet request and response using @Context. It works fine under 7.1.1 but is always null under Wildfly.

I read through the migration guide at:

https://docs.jboss.org/author/display/WFLY8/How+do+I+migrate+my+application+from+AS5+or+AS6+to+WildFly

and didn't see anything that referenced this.

Under 7.1.1, this is the security interceptor with the details in the middle removed:

@Provider
@ServerInterceptor
@SecurityPrecedence
public class SecurityInterceptor implements PreProcessInterceptor {

   @Context
   private HttpServletRequest _servletRequest;
   @Context
   private HttpServletResponse _servletResponse;

   @Override
   public ServerResponse preProcess(HttpRequest request, ResourceMethod method) throws Failure {
      // _servletRequest and _servletResponse are set correctly and are non-null
   }
}

I changed the security interceptor to comply with Resteasy 3.x (some classes were deprecated) and it now looks like this:

@Provider
public class SecurityInterceptor implements ContainerRequestFilter {

    @Context
    private HttpServletRequest _servletRequest;
    @Context
    private HttpServletResponse _servletResponse;

    @Override
    public void filter(ContainerRequestContext requestContext) throws Failure {
        // _servletRequest and _servletResponse are always NULL
    }
}

I tried loading the request and response from the RestEasyProviderFactory like this

@Provider
public class SecurityInterceptor implements ContainerRequestFilter {

    private HttpServletRequest _servletRequest;
    private HttpServletResponse _servletResponse;

    @Override
    public void filter(ContainerRequestContext requestContext) throws Failure {
        _servletRequest = ResteasyProviderFactory.getContextData(HttpServletRequest.class);
        _servletResponse = ResteasyProviderFactory.getContextData(HttpServletResponse.class);

        // _servletRequest and _servletResponse are now correct
    }
}

and that works. So just the @Context injection is not working.

Is there something that needs to be set up differently in Wildfly for this to work?

UPDATE:

I've looked at context injection in a resource class. I'm starting to think that class-level injection the problem. Method level injection seems to work fine. Here is a resource example that shows the problem:

@Path("/mypath")
@Produces({MediaType.APPLICATION_JSON})
public class MyResource {
    @Context
    private HttpServletRequest _httpServletRequest;

    @GET
    @Path("/path1")
    public String test1() {
        // _httpServletRequest is null here
    }

    @GET
    @Path("/path2")
    public String test2(@Context HttpServletRequest request) {
        // request is correct
    }

}

Was class-level injection removed in Wildfly or does it have to be enabled in some way?

Chuck M
  • 1,175
  • 3
  • 17
  • 26

2 Answers2

1

Injection HttpServletRequest via @Context is working on Wildfly out of the box. As already answered here RESTeasy supports the injection of:

  • javax.ws.rs.core.HttpHeaders
  • javax.ws.rs.core.UriInfo
  • javax.ws.rs.core.Request
  • javax.servlet.HttpServletRequest
  • javax.servlet.HttpServletResponse
  • javax.servlet.ServletConfig
  • javax.servlet.ServletContext
  • javax.ws.rs.core.SecurityContext

The JAX-RS specification demands that this injection must work in @Providers like a ContainerRequestFilter (Chapter 9):

Such information is available to Application subclasses (see Section 2. 1), root resource classes (see Chapter 3), and providers (see Chapter 4). This chapter describes these facilities.

However, seems like you can easily skip this feature if RESTeasy finds a beans.xml in the classpath and you take care of creating the Filter class in your Application on your own like here:

@ApplicationPath("/")
public class RestApplication extends Application {

    @Override
    public Set<Object> getSingletons() {
        HashSet<Object> singletons = new HashSet<>();
        singletons.add(new SecurityInterceptor());
        return singletons;
    }

}

If both is the case RESTeasy won't inject on class-level any more.

A simple testcase can be found on github.

Community
  • 1
  • 1
lefloh
  • 10,653
  • 3
  • 28
  • 50
  • I use the Application class to initialize RestEasy exactly as you stated. Are you saying that messes up injection? I was under the impression that was the preferred way to initialize. Also, that is exactly how I initialized under Resteasy 2.x and it worked then. In addition, injection works on the method level in my resource classes. However class-level injection doesn't work anywhere. – Chuck M Aug 14 '14 at 02:10
  • From the userguide: "If you return any empty set for by classes and singletons, your WAR will be scanned for JAX-RS annotation resource and provider classes". This is the way I would prefer. And yes, if you create the singleton and don't inject on creation time nobody will inject. I don't know why this worked for you in RESTeasy 2.x. I'm also not sure if this clashes with the `getSingletons()` documentation: "Fields and properties of returned instances are injected with their declared dependencies (see Context) by the runtime prior to use." – lefloh Aug 14 '14 at 05:10
  • I got it working by following your advice of removing the resources from the Application subclass and letting it scan on its own. I didn't think it was working but it turned out to be an issue with IntelliJ. Deploying from a WAR built through Gradle works. I still have other problems but this one is solved. Appreciate the help. – Chuck M Aug 14 '14 at 17:48
  • Updated my answer after some more investigation. – lefloh Aug 19 '14 at 15:35
0

As far as I am aware, @Context injection into Filter implementations is not supported. You need to get the request/response from the incoming context.

John Ament
  • 11,595
  • 1
  • 36
  • 45
  • Under Resteasy 2.x, I was using a PreProcessInterceptor instead of a ContainerRequestFilter. The context injection worked there, but PreProcessInterceptor was deprecated for Resteasy 3.x. I just tried rolling back to the PreProcessInterceptor and the context injection still does not work. – Chuck M Aug 13 '14 at 13:31
  • Injection is supported in every `@Provider`. See Chapter 9 of the [JAX-RS specifiation](http://download.oracle.com/otn-pub/jcp/jaxrs-2_0-fr-eval-spec/jsr339-jaxrs-2.0-final-spec.pdf) – lefloh Aug 13 '14 at 21:39