使用guice将运行时参数传递给构造函数

wul*_*pro 4 java dependency-injection guice

如果我有以下课程:

public class ObjectDAOMongoDBImpl<T> extends GenericDAOMongoDBImpl<T, ObjectId> implements ObjectDAO<T> {
    public ObjectDAOMongoDBImpl(Class<T> entityClass, Mongo mongo, Morphia morphia, String dbName) {
        super(entityClass, mongo, morphia, dbName);
    }
}
Run Code Online (Sandbox Code Playgroud)

其中,entityClass提供在运行时-我该如何使用吉斯到上述类型的接口绑定?

public class RunnerModule extends AbstractModule {      
    @Override
    protected void configure() {
        bind(GenericDAO.class).to(ObjectDAOMongoDBImpl.class);
    }
}

public class Runner<T, V> {
    GenericDAO<T, V> dao;

    @Inject
    public Runner(GenericDAO<T, V> dao) {
        this.dao = dao;
    }

    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new RunnerModule());
        injector.getInstance(Runner.class);
    }
}
Run Code Online (Sandbox Code Playgroud)

可以定义mongo,morphiadbName作为文字RunnerModule(是否有更简洁的方法?),但我无法知道什么entityClass是运行时.

Koh*_*ert 5

这不是Guice惯用的,也不是它的主要焦点.

jfpoilpret已经说了所有可以说的,但我想从另一个方向解决问题,你可以选择(可能)通过失去类型安全来解决你的问题.

因此,在您的代码中,您要求Guice Runner<T, V>像这样获取您的类的实例

injector.getInstance(Runner.class);
Run Code Online (Sandbox Code Playgroud)

但Guice无法解决这个问题,因为Runner<T, V>它具有依赖性GenericDAO<T, V>,但您没有绑定它的确切实现.正如jfpoilpret所说,你必须在你的模块中为它绑定一些具体的实现.

我猜你想根据一些输入数据确定GenericDAO<T, V>传递给你的确切实现Runner<T, V>,这些数据的类型在编译时是未知的.现在,我们假设您有两个实现.

bind(new TypeLiteral<GenericDAO<String, ObjectID>>(){}).to(StringDAO.class);
bind(new TypeLiteral<GenericDAO<Double, ObjectID>>(){}).to(IntegerDAO.class);
Run Code Online (Sandbox Code Playgroud)

根据不同类型的输入,您可以执行此操作

Injector injector = Guice.createInjector(new RunnerModule());

// possible input which you get from *somewhere* dynamically
Object object = 1.0;

TypeLiteral<?> matchedTypeLiteral = null;
for (Key<?> key : injector.getAllBindings().keySet()) {
  TypeLiteral<?> typeLiteral = key.getTypeLiteral();
  Type type = typeLiteral.getType();
  if (type instanceof ParameterizedType) {
    ParameterizedType parameterizedType = (ParameterizedType) type;
      if (parameterizedType.getRawType() == GenericDAO.class) {
        List<Type> actualTypeArguments =    Arrays.asList(parameterizedType.getActualTypeArguments());
        if (actualTypeArguments.get(0) == object.getClass())
          matchedTypeLiteral = typeLiteral;
    }
  }
};

Runner<?, ?> runner = new Runner<>((GenericDAO<?, ?>) injector.getInstance(Key.get(matchedTypeLiteral)));
System.out.println(runner.dao.getClass()); // IntegerDAO.class
Run Code Online (Sandbox Code Playgroud)

如果Object object = "string";,那么将找到其他实现.这当然相当丑陋,可以通过检查子类和东西来改进,但我认为你明白了.最重要的是你无法解决这个问题.

如果你设法做到(绕过它),请给我发电子邮件,因为我想知道它!我不久前遇到了同样的问题.我写了一个简单的BSON编解码器,我想根据某些任意输入的类型加载通用接口的特定实现.这适用于Java-to-BSON映射,但我不能以任何合理的方式做到这一点,所以我选择了一个更简单的解决方案.