4

I'm migrating a JavaSE application from Jersey 2.x to 2.26. The application relies on HK2 for dependency injection.

Unfortunately some of the official documentation - custom injection, chapter 23 - is now incorrect and has not yet been updated. In his answer here, Paul explains how to migrate a HK2 Factory to a Supplier, which jersey now uses to set up a custom injection provider. Works great, but I'd like to ask for help for the rest of the chapter:

How do I setup a custom injection annotation?

Currently, my existing custom-injection-resolver classes (exactly as per the documentation) compile fine. I'm not sure if they should continue to implement org.glassfish.hk2.api.InjectionResolver direcly? In the javadocs, I find InjectionResolverWrapper, do I need to extend that instead?

The real problem is how to bind the injection resolver to the custom injection. This does not compile:

            bind(SessionInjectResolver.class)
                .to(new TypeLiteral<InjectionResolver<SessionInject>>(){})
                .in(Singleton.class);

I'd very much appreciate an example how to make injection with custom annotations work on Jersey 2.26 again.

Hank
  • 4,597
  • 5
  • 42
  • 84
  • I was just playing around with it for a little bit and found that `bind(new SessionInjectioResolver())` works. But I haven't figured out how to get the injections inside the resolver to work. That's usually where binding as a class comes into play, but I haven't figured that one out yet. – Paul Samsotha Mar 16 '18 at 15:06
  • 1
    Also check [this out](https://github.com/jersey/jersey/blob/12e5d8bdf22bcd2676a1032ed69473cf2bbc48c7/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/internal/PersistenceUnitBinder.java#L136). It still registers the resolver as an instance but it uses `GenericType` instead of `TypeLiteral`. I just tried that, but it doesn't seem to work with the resolver class. I still need to use the instance, just like in the linked code – Paul Samsotha Mar 16 '18 at 15:10
  • Awesome, Paul: `GenericType` fixed it for me. I'll post the complete answer. – Hank Mar 16 '18 at 19:46

1 Answers1

5

Thanks to Paul's comment about using GenericType, here is one solution that works for me on Jersey 2.26 again. It's using the org.glassfish.hk2.api.* classes.

AbstractBinder

.... 

@Override
protected void configure() {
    /*
    Adds binding for @CurrentUser.
    By default, factories are being injected with PerLookup scope.
    */
    bindFactory(CurrentUserSupplier.class)
            .to(User.class)
            .proxy(true)
            .proxyForSameScope(false)
            .in(RequestScoped.class);
    bind(CurrentUserResolver.class)
            .to(new GenericType<InjectionResolver<CurrentUser>>(){})
            .in(Singleton.class);
}
....

CurrentUserSupplier

public class CurrentUserSupplier implements Supplier<User> {

    // inject what is required

    @Override
    public User get() {
        // do what is necessary to obtain User
    // and return it
    }

}

CurrentUserResolver

import org.glassfish.hk2.api.Injectee;
import org.glassfish.hk2.api.InjectionResolver;
import org.glassfish.hk2.api.ServiceHandle;

public class CurrentUserResolver implements InjectionResolver<CurrentUser> {

    @Inject
    @Named(InjectionResolver.SYSTEM_RESOLVER_NAME)
    InjectionResolver<Inject> systemInjectionResolver;

    @Override
    public Object resolve(Injectee injectee, ServiceHandle<?> handle) {
        if (User.class == injectee.getRequiredType()) {
            return systemInjectionResolver.resolve(injectee, handle);
        }

        return null;
    }

    @Override
    public boolean isConstructorParameterIndicator() {
        return false;
    }

    @Override
    public boolean isMethodParameterIndicator() {
        return false;
    }
}
Hank
  • 4,597
  • 5
  • 42
  • 84