I have an interface with a naive implementation, say
interface MyService { void doIt(); } class MyServicePlain implements MyService{ @Inject SomeOtherInterface public void doIt () { } }
I want to make a cache that caches the doIt
, so I wrote a wrapper :
class CachingMyService implements MyService { @Inject MyService inner; int cacheThingie; public int doIt() { if (cached) ... { return cacheThingie; } else { result = inner.doIt(); addToCache(result); return result; } } }
Then, I add both implementations to my Binder:
public class ApplicationBinder extends AbstractBinder { protected void configure() { this.bind(MyServicePlain.class).to(MyService.class).in(Singleton.class).ranked(2); this.bind(CachingMyService.class).to(MyService.class).in(Singleton.class).ranked(2); } }
I get errors complaining about:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=MyService,parent=CachingMyService},position=-1,optional=false,self=false,unqualified=null,1102650897)
I trief using Qualitifaction like this:
@Qualifier @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER}) public @interface NonCached { } @NonCached class MyServicePlain implements MyService{ }
And using that:
class CachingMyService implements MyService { @Inject @NonCached MyService inner;
But that does not work either.
What is the proper way to wrap a caching service like this? And how can I make hk2 choose the proper implementations?
Advertisement
Answer
You need to use the qualifiedBy(Annotation)
method when you want to qualify different types. You also need to annotate each injection point with a different qualifier annotation.
First you need the annotations and have a way to get an instance of them (the qualifiedBy
method requires an annotation instance)
@Qualifier @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER}) public @interface NonCached { class Literal extends AnnotationLiteral<NonCached> implements NonCached { public static final NonCached INSTANCE = new Literal(); private Literal() { } } } @Qualifier @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER}) public @interface Cached { class Literal extends AnnotationLiteral<Cached> implements Cached { public static final Cached INSTANCE = new Literal(); private Literal() { } } }
Then when you bind them used qualifiedBy
this.bind(MyServicePlain.class).to(MyService.class) .in(Singleton.class).qualifiedBy(NonCached.Literal.INSTANCE); this.bind(CachingMyService.class).to(MyService.class) .in(Singleton.class).qualifiedBy(Cached.Literal.INSTANCE);
Then when you inject them, add the applicable qualifier
@Inject @NonCached MyService service; @Inject @Cached MyService service;