抽象超类中的泛型@Inject字段

2022-09-01 23:56:31

考虑一组类似 MVP 的类型。存在一个抽象的表示器,具有视图界面:

public interface View {
    //...
}

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

然后,让我们有一个特定的具体表示器子类,以及它的视图接口和实现:

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(v1 和 Google 的 2.0-SNAPSHOT)中,这会产生错误,因为它无法确定在为 创建绑定连接时是什么。另一方面,Guice 认为,因为它实际上是在创建一个 ,所以它需要一个 .VAbstractPresenter<V>LoginPresenterLoginView

匕首 1.2.2:

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

匕首2.0快照:

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)

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

请注意,当称为 、 等时,也会发生同样的问题。VProvider<V>Lazy<V>


答案 1

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

其余的是Dagger2,我使用的是2.1-SNAPSHOT。您没有提供将进行注入的示例,如果没有它,Dagger2 2.1-SNAPSHOT实际上不会报告问题。它可能已经解决了您的问题,我看到的版本略有不同,但如果没有,那么我假设您的组件看起来像这样:@Component

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

当 Dagger2 处理此内容时,它无法确定 的具体类型,因此它不知道要插入哪种类型。它不能只是插入说,因为如果它被传递了一个.,那会中断。VLoginViewAbstractPresenter<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);
    //...
    }
}

答案 2

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

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

推荐