Dagger: DI on generic class where a superclasses generic type is a generated class

Created on 8 Oct 2016  路  9Comments  路  Source: google/dagger

I'm currently building an app with Dagger 2 and Android DataBinding. I have a generic Activity base class in which the generic type specifies what ViewDataBinding subclass any child activities use for their UI.

public abstract class BaseActivity<T extends ViewDataBinding> extends AppCompatActivity {
    @Inject
    protected EventBus mEventBus;
    @Inject
    protected T mBinding;

    ...
}

public class MainActivity extends BaseActivity<ActivityMainBinding> {
    ...
}

Whenever I attempt to build my project the compilation fails and Dagger 2 gives no indication as to what the underlying issue is. After a lot of trial and error I could only find one answer; it seems as though Dagger 2 doesn't like having a Component that injects into a generic class whose generic type is a generated class (i.e. ActivityMainBinding in the above example). If I remove the generic type from even MainActivity (i.e. make it default to using ViewDataBinding) it builds and runs as expected.

Is there any solution to this?

Most helpful comment

I encountered this issue when using an abstract generic base class
with a single type parameter that is bound to extend ViewDataBinding.
When extending this base class and defining the concrete generated
data binding class and trying to inject into the subclass
(when the base class has any kind of injections) dagger fails to generate the MembersInjector
for the base class since it cannot find the symbol for the generated data binding class.
build config: dagger 2.8, android-gradle-plugin 2.2.3, gradle 3.2.1, build-tools 25.0.2.
Also tried to use the latest android-gradle-plugin(2.3.0-beta2) and gradle(3.3).
Tried to use android gradle plugin's annotation processing support
available since version 2.2.0 and the good old android-apt plugin.

public abstract class BindableBaseController<B extends ViewDataBinding> extends BaseController {
  @Inject void setupLeakCanary(LeakCanaryProxy leakCanaryProxy) {
    addLifecycleListener(new LeakCanaryControllerLifecycleListener(leakCanaryProxy));
  }
  ...
}

public final class LoginController extends BindableBaseController<LoginControllerBinding> {
  @Override protected void injectDependencies() {
    ComponentFinder.<LoginActivityComponent>findActivityComponent(getActivity()).plus(
        new LoginControllerModule()).inject(this);
  }
  ...
}

the error:
"Note: Generating a MembersInjector for *.login.LoginController. Prefer to run the dagger processor over that class instead.
Error:(23, 46) error: cannot find symbol class LoginControllerBinding
where B is a type-variable:
B extends ViewDataBinding declared in class BindableBaseController_MembersInjector"

the generated members injector:

@Generated(
  value = "dagger.internal.codegen.ComponentProcessor",
  comments = "https://google.github.io/dagger"
)
public final class BindableBaseController_MembersInjector<B extends ViewDataBinding>
    implements MembersInjector<BindableBaseController<LoginControllerBinding>> {
  private final Provider<LeakCanaryProxy> leakCanaryProxyProvider;

  public BindableBaseController_MembersInjector(Provider<LeakCanaryProxy> leakCanaryProxyProvider) {
    assert leakCanaryProxyProvider != null;
    this.leakCanaryProxyProvider = leakCanaryProxyProvider;
  }

  public static <B extends ViewDataBinding>
      MembersInjector<BindableBaseController<LoginControllerBinding>> create(
          Provider<LeakCanaryProxy> leakCanaryProxyProvider) {
    return new BindableBaseController_MembersInjector<B>(leakCanaryProxyProvider);
  }

  @Override
  public void injectMembers(BindableBaseController<LoginControllerBinding> instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    ((BaseController) instance).setupLeakCanary(leakCanaryProxyProvider.get());
  }
}

Is there any way to make sure the generated data binding class is generated and available to use by dagger's generated code?

All 9 comments

What errors are you seeing? One guess I would presume is that there might be some missing bindings when T isn't exactly ViewDataBinding.

The only errors I see are during at compile time "cannot find symbol " messages for all of my Dagger generated Component classes and the generated ViewDataBinding classes. It might also be worth pointing out that none of the other classes generated by some other libraries I'm using (such as GreenDao) give any exceptions even when the build fails due to this issue.

I'm not convinced that missing bindings is the issue since If I remove the generics from the BaseActivity class and simply "inject" the bindings myself in each Activity subclass I get no issues at all.

So after deciding to move away from making my BaseActivity a generic class I decided to try it again. I attempted to rebuild my Activity injection code from scratch and now I seem to have things working as desired. My project now compiles and runs as expected. At this moment I have absolutely no idea what I have done differently because there are no major differences between my current code and the broken code. However it's safe to say that my code was at fault and this issue should be closed. Sorry about that.

Ok! If you find any other evidence let us konw!

I encountered this issue when using an abstract generic base class
with a single type parameter that is bound to extend ViewDataBinding.
When extending this base class and defining the concrete generated
data binding class and trying to inject into the subclass
(when the base class has any kind of injections) dagger fails to generate the MembersInjector
for the base class since it cannot find the symbol for the generated data binding class.
build config: dagger 2.8, android-gradle-plugin 2.2.3, gradle 3.2.1, build-tools 25.0.2.
Also tried to use the latest android-gradle-plugin(2.3.0-beta2) and gradle(3.3).
Tried to use android gradle plugin's annotation processing support
available since version 2.2.0 and the good old android-apt plugin.

public abstract class BindableBaseController<B extends ViewDataBinding> extends BaseController {
  @Inject void setupLeakCanary(LeakCanaryProxy leakCanaryProxy) {
    addLifecycleListener(new LeakCanaryControllerLifecycleListener(leakCanaryProxy));
  }
  ...
}

public final class LoginController extends BindableBaseController<LoginControllerBinding> {
  @Override protected void injectDependencies() {
    ComponentFinder.<LoginActivityComponent>findActivityComponent(getActivity()).plus(
        new LoginControllerModule()).inject(this);
  }
  ...
}

the error:
"Note: Generating a MembersInjector for *.login.LoginController. Prefer to run the dagger processor over that class instead.
Error:(23, 46) error: cannot find symbol class LoginControllerBinding
where B is a type-variable:
B extends ViewDataBinding declared in class BindableBaseController_MembersInjector"

the generated members injector:

@Generated(
  value = "dagger.internal.codegen.ComponentProcessor",
  comments = "https://google.github.io/dagger"
)
public final class BindableBaseController_MembersInjector<B extends ViewDataBinding>
    implements MembersInjector<BindableBaseController<LoginControllerBinding>> {
  private final Provider<LeakCanaryProxy> leakCanaryProxyProvider;

  public BindableBaseController_MembersInjector(Provider<LeakCanaryProxy> leakCanaryProxyProvider) {
    assert leakCanaryProxyProvider != null;
    this.leakCanaryProxyProvider = leakCanaryProxyProvider;
  }

  public static <B extends ViewDataBinding>
      MembersInjector<BindableBaseController<LoginControllerBinding>> create(
          Provider<LeakCanaryProxy> leakCanaryProxyProvider) {
    return new BindableBaseController_MembersInjector<B>(leakCanaryProxyProvider);
  }

  @Override
  public void injectMembers(BindableBaseController<LoginControllerBinding> instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    ((BaseController) instance).setupLeakCanary(leakCanaryProxyProvider.get());
  }
}

Is there any way to make sure the generated data binding class is generated and available to use by dagger's generated code?

@ronshapiro Can you or any other team member take a look at this issue?

I ran into the same problem a couple of days ago.

Here's a minimal example of this issue/bug : https://github.com/filkra/DaggerDataBinding

I just followed Dagger's Android Tutorial and created a generic base class (which extends DaggerAppCompatActivity) for my Activities.

Trying to build this projects leads to following error(s):

error: cannot find symbol class ActivityMainBinding

error: cannot find symbol class ActivityMainBinding
where T is a type-variable:
T extends ViewDataBinding declared in class BaseActivity_MembersInjector

error: cannot find symbol class ActivityMainBinding
where T is a type-variable:
T extends ViewDataBinding declared in class BaseActivity_MembersInjector

Error: Execution failed for task ':app:compileDebugJavaWithJavac'.

It seems like Dagger is not able to find classes generated by Android's Data Binding Library.

Thanks to anyone trying to solve this issue.

Can you file a new issue and link to this one?

Sure, opened #698 just now. Thanks.

Was this page helpful?
0 / 5 - 0 ratings