3

I have a ResourceFilterFactory that returns a ContainerRequestFilter if an annotation is present on the AbstractMethod.

The filter reads a cookie or API key and checks that it is still valid, and sets a property on the request. The check is expensive, so I only want it to occur when the annotation is present.

I want to inject the resulting object into my resource, but it seems that injection happens before ResourceFilterFactory filters are applied. If I add the filter to the ResourceConfig as a PROPERTY_CONTAINER_REQUEST_FILTERS, then it happens before the injection, but it does not have access to the AbstractMethod.

How do I bridge the gap, so that the filter is applied and the field is injected only if the method has the annotation?

My code looks something like this. AuthFilter is called after UserIdProvider, so c.getProperties().get(USER_ID_PROPERTY) is always null.

public class AuthFilter implements ContainerRequestFilter {
  public ContainerRequest filter(ContainerRequest request) {
    Integer userId = …; // expensive lookup
    request.getProperties().set(USER_ID_PROPERTY, userId);
    return request;
  }
}

public class AuthFilterFactory implements ResourceFilterFactory {
  // …
  public List<ResourceFilter> create(AbstractMethod am) {
    if (am.isAnnotationPresent(RequireAuth.class) || am.getResource().isAnnotationPresent(RequireAuth.class)) {
      return Collections.singletonList(new ResourceFilter() {
        public ContainerRequestFilter getRequestFilter() {
          return authFilter;
        }
      });
    }
    else {
      return null
    }
  }
}

InjectableProvider:

@Provider
public class UserIdProvider implements InjectableProvider<UserId, Parameter> {
  public ComponentScope getScope() {
    return ComponentScope.PerRequest;
  }

  public Injectable<? extends Object> getInjectable(ComponentContext ic, UserId a, final Parameter t) {
    return new AbstractHttpContextInjectable<Integer>() {
      public Integer getValue(HttpContext c) {
        return (Integer) c.getProperties().get(USER_ID_PROPERTY);
      }
    }
  }
}

Resource:

@Path("/user")
public class UserResource {
  @UserId
  Integer userId;

  // userId should only be set on this method
  @GET
  @RequireAuth
  public UserDetails get() {
    // …
  }

  // the auth filter should not be called for this method
  @POST
  @Path("/login")
  public String login() {
    // …
  }
}
also
  • 974
  • 7
  • 21
  • So you need a filter that runs after the request has been matched, but before the matched resources have been instantiated. This isn't possible with Jersey 1.x afaik, not sure about Jersey 2.x – HiJon89 Oct 29 '13 at 20:49

0 Answers0