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?
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;