Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jersey 2.*. How to replace InjectableProvider and AbstractHttpContextInjectable of Jersey 1.*

Tags:

I would like to create a class whose objects can be injected using the @Context annotation (or better yet a custom annotation for cases where I need to pass an argument to the annotation) into resource methods. In Jersey 1.* I would have used InjectableProvider (in my case together with AbstractHttpContextInjectable). What I'm trying to achieve is something like @Auth [1] from dropwizard (which uses Jersey 1.7).

The injection capabilities of Jersey were replaced by HK2 as far as I know and I could not find any example of what I'm describing.

Edit: See this question for further problems I have encountered while trying to follow Michal's guide.

like image 635
TheCuriousOne Avatar asked Aug 27 '13 10:08

TheCuriousOne


2 Answers

You need to implement InjectionResolver<T> interface from HK2. Take a look at existing implementations that are present in Jersey workspace:

  • ContextInjectionResolver handling @Context
  • ParamInjectionResolver handling @PathParam, @QueryParam, ... (via it's subclasses)
  • AutowiredInjectResolver handling @Autowired

Once you have this, you need to extend AbstractBinder from HK2 and bind your InjectionResolver via it's #configure() method:

public class MyResolverBinder extends AbstractBinder {

    @Override
    protected void configure() {
        bind(MyInjectionResolver.class)
                .to(new TypeLiteral<InjectionResolver<MyAnnotation>>() {})
                .in(Singleton.class);
    }
}

... and register an instance of this binder in your application class (or via feature):

Feature:

public class MyFeature implements Feature {

    @Override
    public boolean configure(final FeatureContext context) {
        context.register(new MyResolverBinder());
        return true;
    }
}

register MyFeature into Application:

public class JaxRsApplication extends Application {

    @Override
    public Set<Class<?>> getClasses() {
        final HashSet<Class<?>> classes = new HashSet<Class<?>>();
        classes.add(MyFeature.class);
        // Register other providers or resources.
        return classes;
    }
}

register MyResolverBinder or Feature in the ResourceConfig

new ResourceConfig()
        // Register either MyFeature
        .register(MyFeature.class)
        // or MyResolverBinder
        .register(new MyResolverBinder())
        // Register other providers or resources
        .packages("my.package");
like image 51
Michal Gajdos Avatar answered Nov 02 '22 06:11

Michal Gajdos


Providing an implementation of InjectionResolver only helps with injection, not when resolving values for the parameters of a resource method.

At least with Jersey 2.11, you need to define a ValueFactoryProvider annotated with @Provider.

@Provider
public class MyValueFactoryProvider implements ValueFactoryProvider {

    @Inject
    private MyFactory factory;

    @Override
    public Factory<?> getValueFactory(Parameter parameter) {
        if (parameter.getAnnotation(MyAnnotationParam.class) != null) {
            return factory;
        }

        return null;
    }

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

}

If you also want to get the value injected in, e.g., members and constructor parameters, then InjectionResolver works well.

like image 40
user1012976 Avatar answered Nov 02 '22 06:11

user1012976