Generic @ Inject' d抽象超类中的字段

时间:2014-10-19 04:37:59

标签: java dependency-injection guice dagger

考虑一组MVP-ish类型。存在一个抽象的Presenter,带有View接口:

public interface View {
    //...
}

public abstract class AbstractPresenter<V extends View> {
    @Inject V view;
    //...
}

然后,让我们有一个特定的具体的presenter子类,其视图接口和实现:

public interface LoginView extends View {
    //...
}
public LoginPresenter extends AbstractPresenter<LoginView> {
    //...
}

public class LoginViewImpl implements LoginView {
    //...
}

在Dagger模块中,我们当然会定义一个@Provides方法:

@Provides
LoginView provideLoginView() {
    return new LoginViewImpl();
}

在Guice中你可以用同样的方式写这个,或者只是bind(LoginView.class).to(LoginViewImpl.class)

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

Dagger 1.2.2:

LoginView

Dagger 2.0-SNAPSHOT:

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

我的问题:这是一个错误吗?这是一个缺少的功能吗?或者这是Dagger保护我们的性能问题(GWT RPC中的SerializableTypeOracleBuilder)?

请注意,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) 被称为VProvider<V>等时会出现同样的问题。

2 个答案:

答案 0 :(得分:1)

这看起来像一个错误,因为它不应该抛出异常,但它应该记录一个警告,说明类型参数需要绑定到特定类型。

其余的是Dagger2,我使用的是2.1-SNAPSHOT。你还没有提供一个例子@Component来进行注射,没有它,Dagger2 2.1-SNAPSHOT实际上并没有报告问题。可能它已经修复了你的问题而且我看到了一个略有不同的版本,但如果没有,那么我认为你的组件看起来像这样:

@Component
public interface PresenterComponent {
  <V extends View> void inject(AbstractPresenter<V> presenter);
}

当Dagger2正在处理它时,它无法确定V的具体类型,因此它不知道要插入的类型。它不能插入说LoginView,因为如果传递AbstractPresenter<LogoutView>,它就会中断。

但是,如果您使用以下说法,那么Dagger2可以确定需要将LoginView注入AbstractPresenter<LoginView>并安全地执行此操作。

@Module
public class LoginModule {
  @Provides LoginView provideLoginView() {
    return new LoginViewImpl();
  }
}

@Component(modules = LoginModule.class)
public interface LoginComponent {
    void inject(LoginPresenter presenter);
}

除非您无法控制何时创建对象,例如如果某个框架为您创建它然后传入以供初始化,那么最好在构造函数上使用@Inject,如果可以的话,例如像这样:

public LoginPresenter extends AbstractPresenter<LoginView> {
    //...
    @Inject LoginPresenter(LoginView view) {
        super(view);
    //...
    }
}

答案 1 :(得分:0)

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

bind(new LoginPresenter<LoginViewImpl>(){});
相关问题