google/dagger

Open ContributesAndroidInjector for other classes

PaulWoitaschek opened this issue ยท 16 comments

I'm using Conductor and created a DispatchingAndroidInjector for Controllers (like fragments from a dagger perspective).
That works great.

However I want to make use of the ContributesAndroidInjector annotation because I don't want to go through all the boilerplate of creating subscomponents manually. However dagger fails with an exception that only framework classes are allowed.
What is the reason for that? Can it be done anyways?

This is unlikely to happen. We won't know which @MapKey to apply, base class to bind, etc. It's also likely to be abused for types that really should be constructor injected - I don't know anything about Conductor, but that's something to consider.

You're welcome to fork and do something similar if you'd like.

Controllers are really similar to fragments and it's a real bummer creating so many subcomponents.

Isn't it possible to create some plugin structure where you can define your map @MapKey and base class?

Why can't you just @Inject your controller? or a Provider<Controller>?

The same reason you can't just inject your fragments. The framework does the instantiation.

So this is something you don't reconsider?

It's really pity that the current mechanism is not extensible. I am considering using Conductor and it is quite disappointing. Maybe we should write some gradle plugin which can generate such subcomponents?

Paul's proposal about a custom mapkey and base class seems reasonable

It would be great to eliminate the last piece of remaining boilerplate! In case someone knows how to write an annotation processor here's the original one:
https://github.com/google/dagger/blob/master/java/dagger/android/processor/ContributesAndroidInjectorGenerator.java
Porting it doesn't seem very hard for someone who already did an annotation processor.

I've just pushed a ported dagger.android.processor that enables automatic subcomponent generation by using a custom annotation @ContributesControllerInjector and @ControllerKey:
https://github.com/sevar83/conductor-dagger
It works with only one minor problem. You have to manually add the generated module class to the app component. Don't know the cause of the problem yet. Hope someone could find it.

For anyone interested: I report that my experiment doesn't work. The Dagger compiler collects only its own generated modules but not those for Controllers. By "own" I mean those generated by the @ContributesAndroidInjector annotation not by our custom @ContributesControllerInjector. The result is runtime exception. I suspect the check is inside dagger.internal.codegen.ModuleDescriptor.collectImplicitlyIncludedModules():

// @ContributesAndroidInjector generates a module that is implicitly included in the enclosing
    // module
    private void collectImplicitlyIncludedModules(
        Set<ModuleDescriptor> includedModules, TypeElement moduleElement) {
      TypeElement contributesAndroidInjector =
          elements.getTypeElement("dagger.android.ContributesAndroidInjector");      // <------ HERE
      if (contributesAndroidInjector == null) {
        return;
      }
      for (ExecutableElement method : methodsIn(moduleElement.getEnclosedElements())) {
        if (isAnnotationPresent(method, contributesAndroidInjector.asType())) {
          includedModules.add(
              create(checkTypePresent(implicitlyIncludedModuleName(method), elements)));
        }
      }
    }

I ran into that as well. It would be really useful if there was some added flexibility to facilitate other contributing processors

If any of you guys is interested i created a small library which makes it possible to @ContributesAndroidInjector for every type such as views or conductor controllers.
You can check it out here: https://github.com/IVIanuu/Contributer/

I'm reopening this - given the recent androidx developments and lots of new, smaller libraries, I think it's worth reconsidering opening up support.

@AndroidInjectionKey also simplifies this. And if people want to use class literals, they can use their own map key as well.

yayaa commented

I also need that functionality!

Even submitted an issue a while ago, but back then it was not considered at all.

Really glad to see more people asks for it and now it is indeed in consideration ๐Ÿ˜

Any updates or plans?

Closing this as with Dagger Hilt's release there's unlikely to be significant new features added to Dagger Android.