Java 如何将类注入到';类别<&燃气轮机;clazz';在Guice?

Java 如何将类注入到';类别<&燃气轮机;clazz';在Guice?,java,dependency-injection,guice,Java,Dependency Injection,Guice,我有一个带构造函数的类,例如: @Inject public ClassTest(ITestInterface testInterface, Class<?> clazz){ ... } @Inject 公共类测试(ITestInterface testInterface,Class clazz){ ... } 问题是如何将一个类绑定到一个可以注入这个构造函数的实现上,并且ClassTest绑定会选择正确的类吗 我想在不同的时间点注入不同的类。当我试图解决它时,G

我有一个带构造函数的类,例如:

@Inject
public ClassTest(ITestInterface testInterface, Class<?> clazz){
    ...
}  
@Inject
公共类测试(ITestInterface testInterface,Class clazz){
...
}  
问题是如何将一个类绑定到一个可以注入这个构造函数的实现上,并且
ClassTest
绑定会选择正确的类吗


我想在不同的时间点注入不同的类。当我试图解决它时,Guice给出了一个错误,它无法在
java.lang.Class

上找到任何合适的构造函数。要随时间改变注入值,您可以使用提供程序。然后它可能看起来像这样:

模块配置:

public class SomeModule extends AbstractModule{

    @Override
    protected void configure() {
        bind(Class.class).toProvider(SomeProvider.class);

    }
}
提供者(不是很优雅,但可能是一个开始…):

客户机代码示例:

public static void main(String[] args){
    SomeProvider.setClass(SomeClass.class);
    Injector injector = Guice.createInjector(new SomeModule());
    printFields(injector.getInstance(Class.class));
    SomeProvider.setClass(SomeOtherClass.class);
    printFields(injector.getInstance(Class.class));
}
private static void printFields(Class clazz) {
    Field[] declaredFields = clazz.getDeclaredFields();
    for(Field field : declaredFields){
        System.out.println(field.getName());
    }
}
最后的结果是:

itWorks
itWorksGreat
我认为您必须使用Guice的扩展

基本上,您可以按原样定义
类测试
,但将“变化”依赖项标记为
@Assisted

@Inject
public ClassTest(ITestInterface testInterface, @Assisted Class<?> clazz){
    ...
}  
然后安装特殊类型的模块,为您创建工厂:

// Inside your module
install(new FactoryModuleBuilder().build(ClassTestFactory.class));
然后,无论您需要什么样的
ClassTest
实例,都应该插入
ClassTestFactory
接口:

@Inject
YourLogicClass(ClassTestFactory ctFactory) {
    this.ctFactory = ctFactory;
}
最后,您可以使用它为您想要的每个类对象创建
ClassTest
s:

ClassTest ct1 = ctFactory.create(SomeClass.class);
ClassTest ct2 = ctFactory.create(AnotherClass.class);

但是如果我是你,我真的会重新考虑整个类体系结构,以避免这些事情的需要。

即使没有辅助注入,也可以解决这个问题,只需在创建绑定时使用
TypeLiteral

import javax.inject.Inject;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;

public class ClassTest
{
    static interface ITestInterface {}

    @Inject
    public ClassTest(ITestInterface testInterface, Class<?> clazz)
    {
        System.err.println("testInterface=" + testInterface);
        System.err.println("clazz=" + clazz);
    }

    public static void main(String... argument)
    {
        ITestInterface testObject = new ITestInterface() {};
        Module module = new AbstractModule()
        {
            @Override
            protected void configure()
            {
                binder().bind(ITestInterface.class).toInstance(testObject);
                binder().bind(new TypeLiteral<Class<?>>() {}).toInstance(testObject.getClass());
                //            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            }
        };
        Injector injector = Guice.createInjector(module);
        injector.getInstance(ClassTest.class);
    }
}
不过,我必须同意@VladimirMatveev的观点,这是一个有点不寻常的用例,需要注入
java.lang.Class
对象可能表明存在设计缺陷。我遇到的这种类型的注入的唯一看似有效的例子是类型检查,其中注入的类需要
class
对象来检查其他对象的类型(通过
class.isInstance(…)
),但不希望注入该类的实例(!)(例如,因为它不是一个单例,可能会产生各种其他不想要的对象创建)。尽管如此,即使是这种情况也有点胡闹,可能会以更好的方式解决。 至少,我会使用一个更具体的类型参数,比如
ClassYou永远不应该编写这样的提供程序!它违背了DI概念的全部原因,而且确实是Guice试图删除的东西。嗯……你是对的(不过这仍然是可能的)对你的回答,这真的很好,我不知道这样的解决方案。我想我可以利用它解决我遇到的两个问题
@Inject
YourLogicClass(ClassTestFactory ctFactory) {
    this.ctFactory = ctFactory;
}
ClassTest ct1 = ctFactory.create(SomeClass.class);
ClassTest ct2 = ctFactory.create(AnotherClass.class);
import javax.inject.Inject;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;

public class ClassTest
{
    static interface ITestInterface {}

    @Inject
    public ClassTest(ITestInterface testInterface, Class<?> clazz)
    {
        System.err.println("testInterface=" + testInterface);
        System.err.println("clazz=" + clazz);
    }

    public static void main(String... argument)
    {
        ITestInterface testObject = new ITestInterface() {};
        Module module = new AbstractModule()
        {
            @Override
            protected void configure()
            {
                binder().bind(ITestInterface.class).toInstance(testObject);
                binder().bind(new TypeLiteral<Class<?>>() {}).toInstance(testObject.getClass());
                //            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            }
        };
        Injector injector = Guice.createInjector(module);
        injector.getInstance(ClassTest.class);
    }
}
testInterface=ClassTest$1@3d921e20
clazz=class ClassTest$1