Guice: automate generic class binding
Can you automate generic class bindings? Consider this:
Common interface:
public interface IAction<T> {
T echo(T inst);
}
Long subtype:
public class LongAction implements IAction<Long> {
@Override
public Long echo(Long inst) {return inst;}
}
String subtype:
public class StringAction implements IAction<String> {
@Override
public String echo(String inst) {return inst;}
}
Custom Module: public class CustomModule extends AbstractModule {
@Override
protected void configure() {
//do this automagically?
bind(new TypeLiteral<IAction<String>>() {}).to(StringAction.class);
bind(new TypeLiteral<IAction<Long>>() {}).to(LongAction.class);
//
}
}
home
// i know i can obtain the correct instance
IAction<String> is = injector.getInstance(new Key<IAction<String>>(){});
Is it possible to bind in some way (like a base abstract class, reflection or whatever) the binding of the classes StringAction
and LongAction
? I've tried using reflection to no avail.
source to share
I somehow managed to trick the compiler.
class CustomModule extends AbstractModule {
static class Holder<T> {
Class<T> param;
Class<IAction<T>> klass;
Holder(Class<?> p, Class<IAction<T>> k) {
param = (Class<T>) p;
klass = k;
}
}
// this would be similar to the result of classpath scanning
List<IAction<?>> stuff;
public <T> void bindSome(Class<T> typeParameter, Class<IAction<T>> implementation) {
Type parameterizedType = Types.newParameterizedType(IAction.class, typeParameter);
bind((TypeLiteral<IAction<T>>) TypeLiteral.get(parameterizedType)).to(implementation);
}
public CustomModule() {
stuff = new ArrayList<>();
stuff.add(new StringAction());
stuff.add(new LongAction());
}
@Override
protected void configure() {
for (IAction<?> act : stuff) {
System.out.printf("Configuring %s for %s\n", act.getTypeArguments(), act.getClass());
//the following doesn't work because the compiler cannot understand that
//the 1st argument T is the same T in 2nd argument Class<T>
//bindSome(act.getTypeArguments(), act.getClass());
//w00t? compiler is tricked?? <String> is erased, but the holder preserves proper class?
Holder<String> holder = new Holder(act.getTypeArguments(), (Class<IAction<String>>) act.getClass());
bindSome(holder.param, holder.klass);
//this is what I want to avoid doing manually
//bind(new TypeLiteral<IAction<String>>() {}).to(StringAction.class);
}
}
}
source to share
You will need to do some sort of class scanning if you don't want to explicitly list the implementations. For example Guava has ClassPath support , eg.
Note that scanning against classes is somewhat contrary to Guice's design philosophy. Is it really so much effort to add one line to the module for every implementation you write?
source to share