Search code examples
jerseyjersey-2.0hk2

Define a custom InjectionResolver for @Inject


My goal is to add some additional logic around the System Injection Resolver (to decorate it, so to speak). Basically, I want to register a custom injection resolver (e.g. described here), but for the javax.inject.@Inject Annotation. The setup works if I create a different custom annotation, but not when using @Inject. My implementation is as follows:

Injection Resolver:

@Singleton
@Rank(Integer.MAX_VALUE)
public class InjectInjectionResolver
    implements InjectionResolver<Inject> {

    private final InjectionResolver<Inject> injectionResolver;

    @Inject
    public InjectInjectionResolver(
            @Named(InjectionResolver.SYSTEM_RESOLVER_NAME) final InjectionResolver<Inject> injectionResolver) {
        this.injectionResolver = injectionResolver;
    }

    @Override
    public Object resolve(final Injectee injectee, final ServiceHandle<?> root) {
        throw new RuntimeException("Why is this never called?");
    }

    @Override
    public boolean isConstructorParameterIndicator() {
        return injectionResolver.isConstructorParameterIndicator();
    }

    @Override
    public boolean isMethodParameterIndicator() {
        return injectionResolver.isMethodParameterIndicator();
    }
}

And I register the resolver as follows (inside ResourceConfig):

register(new AbstractBinder() {

        @Override
        protected void configure() {
            bind(InjectInjectionResolver.class).to(new GenericType<InjectionResolver<Inject>>() {}).in(Singleton.class);
        }
    });

What I tried so far:

  • using @Rank
  • using both the org.glassfish.jersey.internal.inject.AbstractBinder or org.glassfish.hk2.utilities.binding.AbstractBinder with TypeLiteral, along with implementing the org.glassfish.hk2.api.InjectionResolver or org.glassfish.jersey.internal.inject.InjectionResolver
  • making sure the same setup works with @CustomAnnotation (where both the constructor and the resolve methods are called)

Does anyone know how to solve this issue?

Versions used: jersey 2.27

EDIT: When I @Inject the InjectionResolver itself, it seems that hk2's org.jvnet.hk2.internal.ThreeThirtyResolver is injected for the org.glassfish.hk2.api.InjectionResolver, while my custom injection resolver is injected for org.glassfish.jersey.internal.inject.InjectionResolver. However, the custom injection resolver is not used for injection.


Solution

  • The following configuration works for me, thanks to @jwells131313 for bringing me back on track. I tried to use fully qualified names, else it's probably from the javax.inject.* package.

    @Singleton
    @Rank(Integer.MAX_VALUE)
    @org.jvnet.hk2.annotations.Service
    public class MyHk2InjectionResolver
        implements org.glassfish.hk2.api.InjectionResolver<Inject> {
    
        private final org.glassfish.hk2.api.InjectionResolver<Inject> injectionResolver;
    
        @Inject
        public MyHk2InjectionResolver(
            @Named(org.glassfish.hk2.api.InjectionResolver.SYSTEM_RESOLVER_NAME) final org.glassfish.hk2.api.InjectionResolver<Inject> injectionResolver) {
            this.injectionResolver = injectionResolver;
        }
    
        // ... required methods, could just delegate to system resolver
    
    }
    

    To register the resolver, we bind it to the correct type (I do it in the ResourceConfig of a jersey application):

    register(new org.glassfish.hk2.utilities.binding.AbstractBinder() {
    
            @Override
            protected void configure() {
                bind(MyHk2InjectionResolver.class)
                        .to(new org.glassfish.hk2.api.TypeLiteral<org.glassfish.hk2.api.InjectionResolver<Inject>>() {})
                        .in(Singleton.class);
            }
        });
    

    With this setup, you can keep using the @Inject annotation and write some custom injection logic around it, possibly using the default system injection resolver as a fallback.