匕首找不到其他注释处理器生成的类

我写了一个简单的注释处理器(只是为了好玩),它将生成一些我在以前的项目中编写的样板代码。它实际上通过收集活动类上的注释来生成一个模块, 如下所示

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

  @ContributesAndroidInjector
  abstract fun providesMainActivity(): MainActivity
}

但是,当我用匕首运行它时,匕首似乎找不到由我的注释处理器生成的类。虽然,类是生成的并存在于生成的目录中,但我可以在源代码中使用它,但是在编译时,dagger会产生以下异常。任何专家建议?

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

这是主要的应用组件。

@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 App : DaggerApplication() {
    override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
        return DaggerAppComponent.builder().addContext(this).build()
    }
}

一切都很完美,如果我自己创建生成的类。不知何故,在编译时,匕首在由我的注释处理器生成时无法找到该类。

在尤里·库利科夫的回答之后,

yurily's answer

您可以看到生成的文件位于同一包中,但也使用完全限定名引用。仍然匕首报告错误。

这是github存储库的链接,如果有人想实验


答案 1

溶液:

  1. 生成 java 代码。 不支持多轮Kapt
  2. 在最早的可能回合中写入生成的文件。

解释:

Javac注释处理器使用舍入而不是定义处理器顺序。所以通常简化的算法是这样的:

  1. 收集所有 java 源代码
  2. 运行所有注释处理器。任何注释处理器都可以使用文件管理器生成新文件。
  3. 收集所有生成的文件,如果有,请再次运行步骤 2。
  4. 如果没有生成任何文件,请再运行一轮,其中 RoundEnvironment.processingOver() 返回 ,表示这是最后一轮。true

这是该过程的一个很好的解释

现在介绍一下 . 使用 javac 来运行注释处理器。为了实现这一点,它首先运行kotlin compliler来生成java存根文件并在它们上运行。目前不支持多轮,这意味着它不会为由注释处理器生成的kotlin类生成java存根。注意:javac仍然使用多个回合,它只是无法拾取生成的kotlin源。kaptKaptjavackapt

所以,回到你的问题。一种可能的选项是将生成的类移动到单独的模块中,如这里所述

但最简单的选择是直接生成java代码,你生成的java类将被自动拾取,启动第二轮注释处理,其中dagger将处理它们。javac

再补充几点:

  • 不要生成你的代码,当它不会触发另一轮。在您看到批注的同一轮中生成它。RoundEnvironment.processingOver() == true
  • 若要使生成的代码对注释处理器可见,请使用 Filer 编写它。

答案 2

新答案我不知何故错过了你正在使用kapt。Kapt可以处理你的类,即使没有完整的限定名称(这很了不起),如果你把它添加到你的build.gradle:

kapt {
    arguments {
        arg("argumentIncremental", 'true')
    }

    correctErrorTypes = true

}

有关此内容的更多信息: https://kotlinlang.org/docs/reference/kapt.html#non-existent-type-correction


前面的答案可能是有用的,因为有人在gradle中对notespationProcessor(apt)有同样的问题。

简答:对 ActivityInjectorModule 使用完全限定的名称:

@dagger.Component(modules = {dagger.android.AndroidInjectionModule.class, com.mallaudin.daggietest.di.AppModule.class, com.mallaudin.daggietest.di.ActivityInjectorModule.class})

或者,将两个文件放在同一个包中。

长答案:Dagger是一个注释处理器,它在编译代码之前运行,并且(可能)在其他注释处理器运行之前运行。未定义处理器的运行顺序。

匕首注释处理器将处理带有@dagger注释的 TypeElement。组件,它将尝试查找所有模块,包括“活动注入器模块.class”。问题是,ActivityInjectorModule可能还没有生成。因此,“ActivityInjectorModule”此时将没有包。Dagger 将假定 ActivityInjectorModule 与 Component 类位于同一包中,并且不会添加导入。对此,通常的解决方法是对生成的类使用完全限定名(如果其他注释处理器使用这些类)。有时将注释处理移动到差异渐变模块是有意义的,但我不认为这是你想要的。


推荐