Search code examples
javaandroiddagger-2annotation-processingannotation-processor

Dagger can not find classes generated by other annotation processor


I have written a simple Annotation Processor (just for fun) that will generate some boilerplate code that I have been writing in my previous project. It actually generates a module like following by collecting annotations on Activity classes

@Module
abstract class ActivityInjectorModule {
  @ContributesAndroidInjector
  abstract fun providesMain2Activity(): Main2Activity

  @ContributesAndroidInjector
  abstract fun providesMainActivity(): MainActivity
}

However, when I run it with dagger, dagger can't seem to find classes generated by my annotation processor. Although, class is generated and present in generated directory, I can use it in my source code but on compilation, dagger produces the following exception. Any expert suggestion?

error: cannot find symbol
@dagger.Component(modules = {dagger.android.AndroidInjectionModule.class, com.mallaudin.daggietest.di.AppModule.class, ActivityInjectorModule.class})
                                                                                                                       ^
  symbol: class ActivityInjectorModule

This is the main app component.

@Singleton
@Component(
    modules = [
        AndroidInjectionModule::class,
        AppModule::class,
        ActivityInjectorModule::class
    ]
)
interface AppComponent : AndroidInjector<App> {


    @Component.Builder
    interface Builder {

        fun addContext(@BindsInstance ctx: Context): Builder

        fun build(): AppComponent
    }
}

ActivityInjectorModule class is generated by annotation processor and exists in the generated directory.

Application class

class App : DaggerApplication() {
    override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
        return DaggerAppComponent.builder().addContext(this).build()
    }
}

Everything works perfectly, if I create the generated class myself. Somehow on compile time, dagger is unable to find the class when generated by my annotation processor.

After Yuriy Kulikov's answer,

yurily's answer

You can see generated file is in the same package but also referenced with fully qualified name. Still dagger reports errors.

Here is the link to github repository if someone wants to experiment


Solution

  • Solution:

    1. Generate java code. Kapt does not support multiple rounds.
    2. Write generated files on earliest possible round.

    Explanation:

    Javac annotation processor uses rounds instead of defining processors order. So normally the simplified algorithm is like that:

    1. Gather all java sources
    2. Run all annotation processors. Any annotation processor can generate new files using Filer.
    3. Gather all generated files and if there are any, run step 2 again.
    4. If there are no files generated, run one more round where RoundEnvironment.processingOver() returns true, signaling this is the last round.

    Here is a pretty good explanation of the process

    Now a bit about kapt. Kapt uses javac to run annotation processors. To make it possible, it runs kotlin compliler first to generate java stub files and runs javac on them. Currently kapt does not support multiple rounds, meaning it does not generate java stubs for kotlin classes, generated by annotation processors. Note: javac still uses multiple rounds, it just can't pick up generated kotlin sources.

    So, back to your question. One possible option is to move your generated classes into a separate module like it's described here.

    But the easiest option is to generate java code directly and your generated java classes will be picked up by javac automatically, launching second round of annotation processing, where dagger will process them.

    Just a few more notes:

    • Do not generate your code when RoundEnvironment.processingOver() == true, it will not trigger another round. Generate it during the same round you see the annotation.
    • To make the generated code visible to annotation processor, write it using Filer.