guice:自动绑定泛型类

时间:2014-11-14 18:03:31

标签: java dependency-injection guice

是否可以自动化泛型类的绑定? 考虑一下:

通用界面:

public interface IAction<T> {
     T echo(T inst);
}

长子类型:

public class LongAction implements IAction<Long> {    
    @Override
    public Long echo(Long inst) {return inst;}
}

字符串子类型:

public class StringAction implements IAction<String> {
    @Override
    public String echo(String inst) {return inst;}
}

自定义模块: 公共类CustomModule扩展了AbstractModule {

@Override
protected void configure() {
  //do this automagically?
  bind(new TypeLiteral<IAction<String>>() {}).to(StringAction.class);
  bind(new TypeLiteral<IAction<Long>>() {}).to(LongAction.class);
  //
}

}

主要

// i know i can obtain the correct instance
IAction<String> is = injector.getInstance(new Key<IAction<String>>(){});

是否有可能以某种方式(例如:基本抽象类,反射或其他)自动绑定StringActionLongAction类的绑定?我尝试使用反射无济于事。

2 个答案:

答案 0 :(得分:0)

如果您不想明确列出实现,则必须进行某种类路径扫描。例如,Guava对其ClassPath类有一些支持。

请注意,类路径扫描与Guice的设计理念有些相反。对于您编写的每个实现,为模块添加一行是否真的需要额外的努力?

答案 1 :(得分:0)

我以某种方式欺骗了编译器。

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);
    }
}
}