Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 通用@Inject';抽象超类中的d字段_Java_Dependency Injection_Guice_Dagger - Fatal编程技术网

Java 通用@Inject';抽象超类中的d字段

Java 通用@Inject';抽象超类中的d字段,java,dependency-injection,guice,dagger,Java,Dependency Injection,Guice,Dagger,考虑一组MVP类型。存在具有视图界面的抽象演示者: public interface View { //... } public abstract class AbstractPresenter<V extends View> { @Inject V view; //... } 在Guice中,您可以用同样的方式编写它,或者只需将(LoginView.class).to(LoginView.class)绑定到(LoginView.class) 然而,在Da

考虑一组MVP类型。存在具有视图界面的抽象演示者:

public interface View {
    //...
}

public abstract class AbstractPresenter<V extends View> {
    @Inject V view;
    //...
}
在Guice中,您可以用同样的方式编写它,或者只需将(LoginView.class).to(LoginView.class)绑定到(LoginView.class)

然而,在Dagger(来自Google的v1和2.0-SNAPSHOT)中,这会产生一个错误,因为在为
AbstractPresenter
创建绑定连接时,它无法确定
V
是什么。另一方面,Guice指出,因为它实际上正在创建一个
LoginPresenter
,所以它需要实现
LoginView

匕首1.2.2:

foo.bar.AbstractPresenter$$InjectAdapter.java:[21,31] cannot find symbol
  symbol:   class V
  location: class foo.bar.AbstractPresenter$$InjectAdapter
Dagger 2.0-SNAPSHOT:

Caused by: java.lang.IllegalArgumentException: V
    at dagger.internal.codegen.writer.TypeNames$2.defaultAction(TypeNames.java:39)
    at dagger.internal.codegen.writer.TypeNames$2.defaultAction(TypeNames.java:36)
    at javax.lang.model.util.SimpleTypeVisitor6.visitTypeVariable(SimpleTypeVisitor6.java:179)
    at com.sun.tools.javac.code.Type$TypeVar.accept(Type.java:1052)
    at dagger.internal.codegen.writer.TypeNames.forTypeMirror(TypeNames.java:36)
    at dagger.internal.codegen.MembersInjectorGenerator.write(MembersInjectorGenerator.java:142)
    at dagger.internal.codegen.MembersInjectorGenerator.write(MembersInjectorGenerator.java:61)
    at dagger.internal.codegen.SourceFileGenerator.generate(SourceFileGenerator.java:53)
    at dagger.internal.codegen.InjectBindingRegistry.generateSourcesForRequiredBindings(InjectBindingRegistry.java:101)
    at dagger.internal.codegen.ComponentProcessor.process(ComponentProcessor.java:149)
我的问题:这是一个bug吗?这是缺少的功能吗?或者这是Dagger保护我们不受的性能问题(GWT RPC中的la SerializableTypeOracleBuilder)


请注意,当
V
被称为
Provider
Lazy
等时,也会出现同样的问题。

这是因为类型参数。当有类型参数时,注入不起作用。你需要这样做

bind(new LoginPresenter<LoginViewImpl>(){});
bind(新的LoginPresenter(){});

这看起来像一个bug,因为它不应该抛出异常,但它应该记录一条警告,解释类型参数需要绑定到特定类型

剩下的是Dagger2,我使用的是2.1-SNAPSHOT。您尚未提供执行注入的示例
@组件
,如果没有它,Dagger2 2.1-SNAPSHOT实际上不会报告问题。有可能它已经解决了您的问题,我看到了一个稍微不同的版本,但如果没有,我认为您的组件看起来像这样:

@Component
public interface PresenterComponent {
  <V extends View> void inject(AbstractPresenter<V> presenter);
}
public LoginPresenter extends AbstractPresenter<LoginView> {
    //...
    @Inject LoginPresenter(LoginView view) {
        super(view);
    //...
    }
}
除非您无法控制对象的创建时间,例如,如果某个框架为您创建对象,然后传入给您进行初始化,否则如果可以,最好在构造函数上使用
@Inject
,例如:

@Component
public interface PresenterComponent {
  <V extends View> void inject(AbstractPresenter<V> presenter);
}
public LoginPresenter extends AbstractPresenter<LoginView> {
    //...
    @Inject LoginPresenter(LoginView view) {
        super(view);
    //...
    }
}
公共登录Presenter扩展了AbstractPresenter{
//...
@注入LoginPresenter(LoginView视图){
超级(视图);
//...
}
}

据我所知,Dagger不支持这个(在IMO中非常有用的)Guice功能。但这也不是不可能实现的。我会问他们,既然Dagger是一个基于代码生成的DI框架,那么它应该如何连接基于泛型的对象图呢?Guice是基于反射的,这意味着在运行时它可以解决所有这些问题。@toadzky一方面,这是正确的,但另一方面,请记住泛型在运行时会被删除-通过相同的参数,反射如何解决?我不是说抽象类没有注入,而是说指定为
LoginView
V
的具体子类不再是泛型的,并且字段的类型可以解析,dagger应该注入超类的字段。它不会像您在运行时想象的那样被完全擦除。guice4使用typeliterals来捕获这些内容并将其解决。这就是为什么不能向注入器请求这样的列表:
injector.getInstance(list.class)
。您必须这样做:
injector.getInstance(new TypeLiteral(){})
,这样它就可以知道您真正想要什么类型的列表。我不是在要求神奇,我是在寻找注释处理器的泛型推断,以注意LoginPresenter将Presenter子类化,并将V转换为LoginView(这通常可以在其他代码生成工具中解决)。TypeLiteral是在运行时创建的,但代码中的anon子类(后面是
{}
)是静态定义为TypeLiteral的子类,T解析为List,因此可以查找。抱歉,您必须使用com.google.inject.TypeLiteral我想告诉您的是,问题不是关于guice:)更重要的是,LoginPresenter不是泛型,它扩展一个泛型超类并指定泛型参数:
LoginPresenter extends AbstractPresenter
。即使Dagger使用像guice这样的绑定,这段代码也不会编译。我的抽象类代码中不存在
inject
风格的方法-在
Provider
字段中创建
LoginPresenter
,或者在父类中创建
@Injecte
d。这是从2.0-snapshot开始测试的,从那时起,我就没有机会重新构建所有基于guice的代码来尝试使用Dagger2。
public LoginPresenter extends AbstractPresenter<LoginView> {
    //...
    @Inject LoginPresenter(LoginView view) {
        super(view);
    //...
    }
}