Dagger 找不到其他注解处理器生成的 类
Dagger can not find classes generated by other annotation processor
我已经编写了一个简单的 Annotation Processor(只是为了好玩),它将生成一些我在之前的项目中编写的样板代码。它实际上通过在 Activity classes
上收集注释来生成如下模块
@Module
abstract class ActivityInjectorModule {
@ContributesAndroidInjector
abstract fun providesMain2Activity(): Main2Activity
@ContributesAndroidInjector
abstract fun providesMainActivity(): MainActivity
}
然而,当我用 dagger 运行 时,dagger 似乎无法找到由我的注释处理器 生成的 classes。虽然 class 已生成并出现在生成的目录中,但我可以在我的源代码中使用它,但在编译时,匕首会产生以下异常。有专家建议吗?
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由注释处理器生成,存在于生成的目录中。
申请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.
在 Yuriy Kulikov 的回答之后,
您可以看到生成的文件在同一个包中,但也使用完全限定名称进行引用。还是dagger报错。
这里是 link 到 github 存储库,如果有人想试验的话
可能有更优雅的方法来解决这个问题,但最简单和最可靠的解决方案是使用 javac
进行两次传递——一次到 运行 只是你的注释处理器,第二个做它通常做的一切。
javac
documentation 指定了两个应该可以帮助您的选项。
-proc: {none,only}
Controls whether annotation processing and/or compilation is done. -proc:none means that compilation takes place without annotation processing. -proc:only means that only annotation processing is done, without any subsequent compilation.
-processor class1[,class2,class3...]
Names of the annotation processors to run. This bypasses the default discovery process.
第一遍(只运行你自己的注解处理器)是
javac -proc:only -processor com.foo.bar.MyProcessor MyProject/src/*
第二遍(常规构建)是
javac MyProject/src/*
如果您使用的是 Ant 或 Maven 之类的东西,您应该能够更新构建指令,只需最少的工作量即可获得两次编译器传递。
编辑:这是我对 Gradle 说明的尝试
我没有使用 Gradle 的经验,但看起来你需要做这样的事情。
在您的 Gradle 构建脚本中,您需要定义预处理任务并将对您的任务的依赖添加到 javaCompile 任务。
javaCompile.dependsOn myAnnotationTask
task myAnnotationTask(type: JavaCompile) {
options.compilerArgs << '-proc:only' << '-processors com.foo.bar.MyAnnotationProcessor'
}
新答案
我不知何故错过了你正在使用 kapt。 Kapt 可以处理你的 classes,即使没有完整的限定名(这很了不起)如果你将它添加到你的 build.gradle:
kapt {
arguments {
arg("argumentIncremental", 'true')
}
correctErrorTypes = true
}
更多相关信息:https://kotlinlang.org/docs/reference/kapt.html#non-existent-type-correction
之前的答案可能有用,因为有人在 gradle 中对 annotationProcessor (apt) 有同样的问题。
简答:使用 ActivityInjectorModule 的完全限定名称:
@dagger.Component(modules = {dagger.android.AndroidInjectionModule.class, com.mallaudin.daggietest.di.AppModule.class, com.mallaudin.daggietest.di.ActivityInjectorModule.class})
或者将两个文件放在同一个包中。
长答案:Dagger 是一个注解处理器,它 运行 在你的代码编译之前并且(可能)在你的其他注解处理器之前 运行秒。未定义处理器 运行 的顺序。
Dagger 注释处理器将处理用@dagger.Component 注释的 TypeElement,它会尝试查找包括 "ActivityInjectorModule.class" 在内的所有模块。问题是,ActivityInjectorModule 可能还没有生成。因此 "ActivityInjectorModule" 此时不会有包。 Dagger 将假定 ActivityInjectorModule 与 Component class 位于同一个包中,并且不会添加导入。通常的解决方法是为生成的 classes 使用完全限定名称,如果它们被其他注释处理器使用的话。有时将注释处理移动到差异 gradle 模块是有意义的,但我不认为这就是你想要的。
解法:
- 生成 java 代码。
Kapt
does not support multiple rounds.
- 尽早写入生成的文件。
解释:
Javac
注释处理器使用回合而不是定义处理器顺序。所以通常简化算法是这样的:
- 收集所有 java 来源
- 运行 所有注释处理器。任何注释处理器都可以使用 Filer.
生成新文件
- 收集所有生成的文件,如果有,运行 再次执行第 2 步。
- 如果没有文件生成,运行 再一轮 RoundEnvironment.processingOver() returns
true
,表明这是最后一轮。
现在谈谈 kapt
。 Kapt
使用 javac 到 运行 注释处理器。为了使其成为可能,它 运行s kotlin 编译器首先 生成 java 存根文件 和 运行s javac
。目前 kapt
does not support multiple rounds,这意味着它不会为注释处理器生成的 kotlin 类 生成 java 存根。
注意:javac
仍然使用多轮,只是无法获取生成的 kotlin 源代码。
所以,回到你的问题。一种可能的选择是将生成的 类 移动到一个单独的模块中,就像 described here.
但最简单的选择是直接生成 java 代码,你生成的 java 类 将被 javac
自动提取,启动第二轮注释处理,dagger 将在其中处理它们。
再补充几点:
- 不要在
RoundEnvironment.processingOver() == true
时生成你的代码,它不会触发另一轮。在您看到注释的同一轮中生成它。
- 要使生成的代码对注释处理器可见,请使用 Filer 编写代码。
我已经编写了一个简单的 Annotation Processor(只是为了好玩),它将生成一些我在之前的项目中编写的样板代码。它实际上通过在 Activity classes
上收集注释来生成如下模块@Module
abstract class ActivityInjectorModule {
@ContributesAndroidInjector
abstract fun providesMain2Activity(): Main2Activity
@ContributesAndroidInjector
abstract fun providesMainActivity(): MainActivity
}
然而,当我用 dagger 运行 时,dagger 似乎无法找到由我的注释处理器 生成的 classes。虽然 class 已生成并出现在生成的目录中,但我可以在我的源代码中使用它,但在编译时,匕首会产生以下异常。有专家建议吗?
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由注释处理器生成,存在于生成的目录中。
申请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.
在 Yuriy Kulikov 的回答之后,
您可以看到生成的文件在同一个包中,但也使用完全限定名称进行引用。还是dagger报错。
这里是 link 到 github 存储库,如果有人想试验的话
可能有更优雅的方法来解决这个问题,但最简单和最可靠的解决方案是使用 javac
进行两次传递——一次到 运行 只是你的注释处理器,第二个做它通常做的一切。
javac
documentation 指定了两个应该可以帮助您的选项。
-proc: {none,only}
Controls whether annotation processing and/or compilation is done. -proc:none means that compilation takes place without annotation processing. -proc:only means that only annotation processing is done, without any subsequent compilation.
-processor class1[,class2,class3...]
Names of the annotation processors to run. This bypasses the default discovery process.
第一遍(只运行你自己的注解处理器)是
javac -proc:only -processor com.foo.bar.MyProcessor MyProject/src/*
第二遍(常规构建)是
javac MyProject/src/*
如果您使用的是 Ant 或 Maven 之类的东西,您应该能够更新构建指令,只需最少的工作量即可获得两次编译器传递。
编辑:这是我对 Gradle 说明的尝试
我没有使用 Gradle 的经验,但看起来你需要做这样的事情。
在您的 Gradle 构建脚本中,您需要定义预处理任务并将对您的任务的依赖添加到 javaCompile 任务。
javaCompile.dependsOn myAnnotationTask
task myAnnotationTask(type: JavaCompile) {
options.compilerArgs << '-proc:only' << '-processors com.foo.bar.MyAnnotationProcessor'
}
新答案 我不知何故错过了你正在使用 kapt。 Kapt 可以处理你的 classes,即使没有完整的限定名(这很了不起)如果你将它添加到你的 build.gradle:
kapt {
arguments {
arg("argumentIncremental", 'true')
}
correctErrorTypes = true
}
更多相关信息:https://kotlinlang.org/docs/reference/kapt.html#non-existent-type-correction
之前的答案可能有用,因为有人在 gradle 中对 annotationProcessor (apt) 有同样的问题。
简答:使用 ActivityInjectorModule 的完全限定名称:
@dagger.Component(modules = {dagger.android.AndroidInjectionModule.class, com.mallaudin.daggietest.di.AppModule.class, com.mallaudin.daggietest.di.ActivityInjectorModule.class})
或者将两个文件放在同一个包中。
长答案:Dagger 是一个注解处理器,它 运行 在你的代码编译之前并且(可能)在你的其他注解处理器之前 运行秒。未定义处理器 运行 的顺序。
Dagger 注释处理器将处理用@dagger.Component 注释的 TypeElement,它会尝试查找包括 "ActivityInjectorModule.class" 在内的所有模块。问题是,ActivityInjectorModule 可能还没有生成。因此 "ActivityInjectorModule" 此时不会有包。 Dagger 将假定 ActivityInjectorModule 与 Component class 位于同一个包中,并且不会添加导入。通常的解决方法是为生成的 classes 使用完全限定名称,如果它们被其他注释处理器使用的话。有时将注释处理移动到差异 gradle 模块是有意义的,但我不认为这就是你想要的。
解法:
- 生成 java 代码。
Kapt
does not support multiple rounds. - 尽早写入生成的文件。
解释:
Javac
注释处理器使用回合而不是定义处理器顺序。所以通常简化算法是这样的:
- 收集所有 java 来源
- 运行 所有注释处理器。任何注释处理器都可以使用 Filer. 生成新文件
- 收集所有生成的文件,如果有,运行 再次执行第 2 步。
- 如果没有文件生成,运行 再一轮 RoundEnvironment.processingOver() returns
true
,表明这是最后一轮。
现在谈谈 kapt
。 Kapt
使用 javac 到 运行 注释处理器。为了使其成为可能,它 运行s kotlin 编译器首先 生成 java 存根文件 和 运行s javac
。目前 kapt
does not support multiple rounds,这意味着它不会为注释处理器生成的 kotlin 类 生成 java 存根。
注意:javac
仍然使用多轮,只是无法获取生成的 kotlin 源代码。
所以,回到你的问题。一种可能的选择是将生成的 类 移动到一个单独的模块中,就像 described here.
但最简单的选择是直接生成 java 代码,你生成的 java 类 将被 javac
自动提取,启动第二轮注释处理,dagger 将在其中处理它们。
再补充几点:
- 不要在
RoundEnvironment.processingOver() == true
时生成你的代码,它不会触发另一轮。在您看到注释的同一轮中生成它。 - 要使生成的代码对注释处理器可见,请使用 Filer 编写代码。