Google guice の bindListener 普遍的な使い方を googlegroup.com で見つけることができた。
インジェクト対象の限定方法として任意のサブクラス(またはimplements)
であることを限定できることだ。
import com.google.inject.TypeLiteral;
import com.google.inject.matcher.AbstractMatcher;
import com.google.inject.matcher.Matcher;
/**
* ClassToTypeLiteralMatcherAdapter
*/
public class ClassToTypeLiteralMatcherAdapter extends AbstractMatcher<TypeLiteral>{
private final Matcher<Class> classMatcher;
public ClassToTypeLiteralMatcherAdapter(Matcher<Class> classMatcher){
this.classMatcher = classMatcher;
}
/*
* @see com.google.inject.matcher.Matcher#matches(java.lang.Object)
*/
@Override
public boolean matches(TypeLiteral typeLiteral){
return this.classMatcher.matches(typeLiteral.getRawType());
}
}
この使い方は、TypeListener と伴に使う
bindListener(new ClassToTypeLiteralMatcherAdapter(Matchers.subclassesOf(Foo.class))
,typelistener);
例えば、Foo という interface を実装するクラスに限定して "a"→"AAA" となるProperties を
注入させる場合、
Injector injector = Guice.createInjector で指定する Module に以下の
ような configure を記述する
@Override
protected void configure(){
bindListener(new ClassToTypeLiteralMatcherAdapter(Matchers.subclassesOf(Foo.class))
,new TypeListener(){
@Override
public <T> void hear(TypeLiteral<T> typeLiteral,TypeEncounter<T> typeEncounter){
for(final Field field : typeLiteral.getRawType().getDeclaredFields()){
if (field.getType()==Properties.class){
field.setAccessible(true);
typeEncounter.register(new MembersInjector<T>(){
@Override
public void injectMembers(T t){
Properties prop = new Properties();
prop.setProperty("a","AAA");
try{
field.set(t,prop);
}catch(IllegalAccessException e){
throw new RuntimeException(e);
}
}
});
}
}
}
});
}
これは、Wicket の WebApplication の init() で
addComponentInstantiationListener(new GuiceComponentInjector(Module...));
を書くケースでも効力を発揮できるであろう。