抽象超类中的Generic @Inject'd字段 [英] Generic @Inject'd fields in an abstract superclass

查看:158
本文介绍了抽象超类中的Generic @Inject'd字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Consider a MVP-ish set of types. An abstract Presenter exists, with a View interface:

public interface View {
    //...
}

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

然后,让我们具体具体presenter子类及其视图接口和实现:

Then, lets have a specific concrete presenter subclass, with its view interface and implementation:

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

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

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

In a Dagger module, of course we would define a @Provides method:

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

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

In Guice you could write this the same way, or just bind(LoginView.class).to(LoginViewImpl.class).

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

However, in Dagger (both v1 and the 2.0-SNAPSHOT from Google), this produces an error, since it can't figure out what V is when creating the binding wiring for AbstractPresenter<V>. On the other hand, Guice figures out that that because it is actually creating a LoginPresenter, so it needs an implementation of LoginView.

Dagger 1.2.2:

Dagger 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:

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)

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

My question: Is this a bug? Is this a missing feature? Or is this a performance issue that Dagger is protecting us from (a la SerializableTypeOracleBuilder in GWT RPC)?

请注意,当 V时会出现同样的问题被称为提供商< V> 懒惰< V> 等。

Note that this same issue occurs when V is referred to as Provider<V>, Lazy<V>, etc.

推荐答案

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

That looks like a bug as it shouldn't throw an exception, but it should log a warning explaining that type parameters need to be bound to a specific type.

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

The rest is for Dagger2, and I'm using 2.1-SNAPSHOT. You haven't provided an example @Component that will do the injection and without it Dagger2 2.1-SNAPSHOT doesn't actually report a problem. It's possible that it has already fixed your problem and I'm seeing a slightly different version but if not then I presume your component looks something like this:

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

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

When Dagger2 is processing this it cannot determine a concrete type for V, and so it doesn't know what type to insert. It can't just insert say LoginView because that would break if it was passed a AbstractPresenter<LogoutView>.

但是,如果您使用以下说法,那么Dagger2可以确定它需要将LoginView注入 AbstractPresenter< LoginView> 安全。

However, if you use say the following then Dagger2 can determine that it needs to inject a LoginView into AbstractPresenter<LoginView> and will do so safely.

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

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

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

Unless you have no control over when an object is created, e.g. if some framework creates it for you and then passes in for you to initialize, it is much better to use @Inject on the constructor if you can, e.g. like this:

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

这篇关于抽象超类中的Generic @Inject'd字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆