java - polimorfismo - implementación de clases abstractas
Campos genéricos @ Inject''d en una superclase abstracta (2)
Esto se debe a los argumentos Tipo. Inyecciones no funciona cuando tienes un tipo de argumentos. Necesito hacer algo como esto,
bind(new LoginPresenter<LoginViewImpl>(){});
Considere un conjunto de tipos MVP-ish. Existe un presentador abstracto, con una interfaz de visualización:
public interface View {
//...
}
public abstract class AbstractPresenter<V extends View> {
@Inject V view;
//...
}
Luego, tengamos una subclase de presentador concreta específica, con su interfaz de vista e implementación:
public interface LoginView extends View {
//...
}
public LoginPresenter extends AbstractPresenter<LoginView> {
//...
}
public class LoginViewImpl implements LoginView {
//...
}
En un módulo Dagger, por supuesto, definiríamos un método @Provides
:
@Provides
LoginView provideLoginView() {
return new LoginViewImpl();
}
En Guice podría escribir esto de la misma manera, o simplemente bind(LoginView.class).to(LoginViewImpl.class)
.
Sin embargo, en Dagger (tanto v1 como 2.0-SNAPSHOT de Google), esto produce un error, ya que no puede determinar qué es V
al crear el cableado de enlace para AbstractPresenter<V>
. Por otro lado, Guice se da cuenta de eso porque en realidad está creando un LoginPresenter
, por lo que necesita una implementación de LoginView
.
Daga 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-INSTANTÁNEA
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)
Mi pregunta: ¿Es esto un error? ¿Esta es una característica que falta? ¿O es este un problema de rendimiento del que Dagger nos está protegiendo (a la manera SerializableTypeOracleBuilder en GWT RPC)?
Tenga en cuenta que este mismo problema ocurre cuando se hace referencia a Provider<V>
como Provider<V>
, Lazy<V>
, etc.
Parece un error, ya que no debería arrojar una excepción, pero debería registrar una advertencia explicando que los parámetros del tipo deben estar vinculados a un tipo específico.
El resto es para Dagger2, y estoy usando 2.1-SNAPSHOT. No ha proporcionado un ejemplo de @Component
que hará la inyección y sin él Dagger2 2.1-SNAPSHOT en realidad no informa un problema. Es posible que ya haya solucionado tu problema y estoy viendo una versión ligeramente diferente, pero si no, supongo que tu componente se ve así:
@Component
public interface PresenterComponent {
<V extends View> void inject(AbstractPresenter<V> presenter);
}
Cuando Dagger2 está procesando esto, no puede determinar un tipo concreto para V
, por lo que no sabe qué tipo insertar. No puede simplemente insertar decir LoginView
porque eso se rompería si se pasara a AbstractPresenter<LogoutView>
.
Sin embargo, si usa lo siguiente, Dagger2 puede determinar que necesita inyectar un LoginView en AbstractPresenter<LoginView>
y lo hará de manera segura.
@Module
public class LoginModule {
@Provides LoginView provideLoginView() {
return new LoginViewImpl();
}
}
@Component(modules = LoginModule.class)
public interface LoginComponent {
void inject(LoginPresenter presenter);
}
A menos que no tenga control sobre cuándo se crea un objeto, por ejemplo, si algún marco lo crea para usted y luego lo @Inject
para que lo inicialice, es mucho mejor usar @Inject
en el constructor si puede, por ejemplo, de esta manera:
public LoginPresenter extends AbstractPresenter<LoginView> {
//...
@Inject LoginPresenter(LoginView view) {
super(view);
//...
}
}