1

Assume I have a following code in Java EE / EJB / JAX-RS:

@POST
@Path("some/path")
@MyAnnotation
public MyResponse createActivation(MyRequest request, CustomValue value) {
   // ...
}

How do I check for the presence of custom @MyAnnotation annotation and populate CustomValue value method parameter based on some request context parameters in case the annotation is present?

Note: I already have this code in Spring using HandlerInterceptorAdapter and HandlerMethodArgumentResolver. Now I need to do the same without Spring. I have already discovered the ContainerRequestFilter and I use it to check for the annotation, but now I am struggling with injecting the method parameter.

Petr Dvořák
  • 750
  • 1
  • 9
  • 21

1 Answers1

0

Custom method parameter injection is handled a little differently from normal (i.e. field, constructor) injection. With Jersey, this requires the implementation of a ValueFactoryProvider. For your case it would look something like

public class MyAnnotationParamValueProvider implements ValueFactoryProvider {

    @Inject
    private ServiceLocator locator;

    @Override
    public Factory<?> getValueFactory(Parameter parameter) {
        if (parameter.getAnnotation(MyAnnotation.class) != null
                && parameter.getRawType() == CustomValue.class) {
            final Factory<CustomValue> factory
                    = new AbstractContainerRequestValueFactory<CustomValue>() {
                @Override
                public CustomValue provide() {
                    final ContainerRequest request = getContainerRequest();
                    final String value = request.getHeaderString("X-Value");
                    return new CustomValue(value);
                }
            };
            locator.inject(factory);
            return factory;
        }
        return null;
    }

    @Override
    public PriorityType getPriority() {
        return Priority.NORMAL;
    }
}

Then you need to register it with the ResourceConfig

public class AppConfig extends ResourceConfig {
    public AppConfig() {
         register(new AbstractBinder() {
              @Override
              protected void configure() {
                  bind(MyAnnotationParamValueProvider.class)
                       .to(ValueFactoryProvider.class)
                       .in(Singleton.class);
              }
         });
    }
}

See a complete example in this Gist

See also:

  • Custom Method Parameter Injection with Jersey. It shows another way to do this, where you don't need to explicitly inject, and also you will be able to inject the value in all three areas (field, constructor, and method param).
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • Thank you for the answer! :) Is there any way to do this without the ResourceConfig class, for example using annotations? I must admin that working with Swift made me soft... :D – Petr Dvořák Dec 19 '16 at 11:16
  • So you are using a web.xml (and package scanning)? If so, check out [this post](http://stackoverflow.com/a/29275727/2587435) – Paul Samsotha Dec 19 '16 at 11:21
  • No, no web.xml... and no package scanning. But based on [this post](http://blog.dejavu.sk/2013/11/19/registering-resources-and-providers-in-jersey-2/), I believe that package scanning can be configured in code as well - I will give it a shot. :) Thank you! – Petr Dvořák Dec 19 '16 at 11:27
  • Then how are you configuring the application? With Standard JAX-RS `Application` class and `@ApplicationPath`? – Paul Samsotha Dec 19 '16 at 11:29
  • 1
    The post I linked to, you can use the same solution, using the `Feature`. If you have an empty `Application` subclass, the classpath scanning will pick up the `@Provider` annotation. Otheriwse you need to register the Feature in your Application class – Paul Samsotha Dec 19 '16 at 11:40