Подтвердить что ты не робот

Общие поля @Inject'd в абстрактном суперклассе

Рассмотрим набор типов MVP-иш. Существует абстрактный докладчик с интерфейсом View:

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).

Однако в кинжале (оба v1 и 2.0-SNAPSHOT от Google) это приводит к ошибке, так как не может определить, что V при создании проводки привязки для AbstractPresenter<V>. С другой стороны, Гис объясняет это тем, что на самом деле он создает LoginPresenter, поэтому ему нужна реализация LoginView.

Кинжал 1.2.2:

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

Кинжал 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 защищает от (a la SerializableTypeOracleBuilder в GWT RPC)?

Обратите внимание, что эта же проблема возникает, когда V называется Provider<V>, Lazy<V> и т.д.

4b9b3361

Ответ 1

Это похоже на ошибку, поскольку она не должна генерировать исключение, но она должна регистрировать предупреждение, объясняющее, что параметры типа должны быть привязаны к определенному типу.

Остальное для Dagger2, и я использую 2.1-SNAPSHOT. Вы не представили пример @Component, который сделает инъекцию, и без него Dagger2 2.1-SNAPSHOT фактически не сообщает о проблеме. Возможно, он уже исправил вашу проблему, и я вижу немного другую версию, но если нет, то я предполагаю, что ваш компонент выглядит примерно так:

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

Когда Dagger2 обрабатывает это, он не может определить конкретный тип для V, и поэтому он не знает, какой тип вставить. Он не может просто вставить say LoginView, потому что это сломается, если он был передан a 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);
    //...
    }
}

Ответ 2

Это из-за аргументов типа. Injects не работает, если у вас есть аргументы типа. U нужно сделать что-то вроде этого,

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