Custom Method Annotation using Jersey's AbstractHttpContextInjectable not Working

annotations, dropwizard, java, jersey

Solution

If you don't want to use AOP, I think you can do this by implementing ResourceMethodDispatchProvider and ResourceMethodDispatchAdapter.

public class CustomDispatchProvider implements ResourceMethodDispatchProvider {

ResourceMethodDispatchProvider provider;

CustomDispatchProvider(ResourceMethodDispatchProvider provider)
{
    this.provider = provider;
}

@Override
public RequestDispatcher create(AbstractResourceMethod abstractResourceMethod) {
    System.out.println("creating new dispatcher for " + abstractResourceMethod);

    RequestDispatcher defaultDispatcher = provider.create(abstractResourceMethod);
    if (abstractResourceMethod.getMethod().isAnnotationPresent(Secure.class))
        return new DispatcherDecorator(defaultDispatcher);
    else
        return defaultDispatcher;
}

@Provider
public static class CustomDispatchAdapter implements ResourceMethodDispatchAdapter
{

    @Override
    public ResourceMethodDispatchProvider adapt(ResourceMethodDispatchProvider provider) {
        return new CustomDispatchProvider(provider);
    }

}

public static class DispatcherDecorator implements RequestDispatcher
{
    private RequestDispatcher dispatcher;

    DispatcherDecorator(RequestDispatcher dispatcher)
    {
        this.dispatcher = dispatcher;
    }

    public void dispatch(Object resource, HttpContext context) {
        if (context.getRequest().isSecure())
        {
            System.out.println("secure request detected");
            this.dispatcher.dispatch(resource, context);
        }
        else
        {
            System.out.println("request is NOT secure");
            throw new RuntimeException("cannot access this resource over an insecure connection");
        }

    }

}
}

In Dropwizard, add the provider like this: environment.addProvider(CustomDispatchAdapter.class);

Problem

I want to restrict some methods if they are being accessed in a non-secure manner. I'm creating a @Secure annotation that checks whether or not the request was sent over secure channels. However, I cannot create a method injectable that captures the HttpContext of the request. ``` @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface Secure { } public class SecureProvider<T> implements InjectableProvider<Secure, AbstractResourceMethod> { @Override public ComponentScope getScope() { return ComponentScope.PerRequest; } @Override public Injectable<?> getInjectable(ComponentContext componentContext, Secure annotation, AbstractResourceMethod method) { return new SecureInjectable(); } } public class SecureInjectable<T> extends AbstractHttpContextInjectable<T> { @Override public T getValue(HttpContext context) { // validation here return null; } } ``` I'm using the Dropwizard framework, so initialization of the Providers should be as easy as: ``` environment.addProvider(new SessionRestrictedToProvider<>(new SessionAuthenticator(), "MySession")); environment.addProvider(new SecureProvider<>()); environment.setSessionHandler(new SessionHandler()); ``` Usage: ``` @Resource @Path("/account") public class AccountResource { @GET @Path("/test_secure") @Secure public Response isSecure() { return Response.ok().build(); } } ``` At this point I'm assuming that a HttpContext Injectable doesn't work on a method, but I'm at a loss as to what other options I could utilize to implement this annotation.

Original source