猿问

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

我已经编写了一个简单的 Annotation Processor(只是为了好玩),它将生成一些我在之前的项目中编写的样板代码。它实际上通过收集 Activity 类上的注解来生成如下所示的模块


@Module

abstract class ActivityInjectorModule {

  @ContributesAndroidInjector

  abstract fun providesMain2Activity(): Main2Activity


  @ContributesAndroidInjector

  abstract fun providesMainActivity(): MainActivity

}

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


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()

    }

}

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


在 Yuriy Kulikov 的回答之后,

您可以看到生成的文件在同一个包中,但也使用完全限定名称进行引用。还是dagger报错。

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


江户川乱折腾
浏览 126回答 3
3回答

拉丁的传说

解决方案:生成java代码。Kapt 不支持多轮。在尽可能早的一轮写入生成的文件。解释:Javac注释处理器使用回合而不是定义处理器顺序。所以通常简化的算法是这样的:收集所有 java 资源运行所有注释处理器。任何注释处理器都可以使用Filer生成新文件。收集所有生成的文件,如果有,请再次运行步骤 2。如果没有生成文件,则再运行一轮RoundEnvironment.processingOver()返回true,表示这是最后一轮。这是对这个过程的一个很好的解释现在有点关于kapt。Kapt 使用 javac运行注解处理器。为了使其成为可能,它首先运行 kotlin compliler 以生成 java 存根文件并javac在其上运行。目前kapt 不支持多轮,这意味着它不会为注释处理器生成的 kotlin 类生成 java 存根。 注意:javac仍然使用多轮,只是无法获取生成的 kotlin 源代码。那么,回到你的问题。一种可能的选择是将您生成的类移动到一个单独的模块中但最简单的选择是直接生成 java 代码,你生成的 java 类将被自动拾取javac,启动第二轮注释处理,dagger 将在其中处理它们。再补充几点:不要在 时生成您的代码RoundEnvironment.processingOver() == true,它不会触发另一轮。在您看到注释的同一轮中生成它。要使生成的代码对注释处理器可见,请使用Filer编写它。

一只名叫tom的猫

新答案 我以某种方式错过了您正在使用 kapt。Kapt 可以处理你的类,即使没有完整的限定名(这很了不起),如果你将它添加到你的 build.gradle 中:kapt {&nbsp; &nbsp; arguments {&nbsp; &nbsp; &nbsp; &nbsp; arg("argumentIncremental", 'true')&nbsp; &nbsp; }&nbsp; &nbsp; 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 类位于同一个包中,并且不会添加导入。通常的解决方法是为生成的类使用完全限定名称,如果它们被其他注释处理器使用的话。有时将注释处理移动到不同的 gradle 模块是有意义的,但我不认为这是你想要的。

尚方宝剑之说

可能有更优雅的方法来解决这个问题,但最简单和最可靠的解决方案是执行两次传递 — 一次javac仅运行注释处理器,第二次执行它通常执行的所有操作。该javac 文档指定了两个可以帮助您的选项。-proc:{无,仅}控制注释处理和/或编译是否完成。-proc:none 表示编译在没有注释处理的情况下进行。-proc:only表示只做注解处理,不做任何后续编译。-处理器类 1 [,类 2,类 3 ...]要运行的注释处理器的名称。这会绕过默认的发现过程。第一步(只运行你自己的注解处理器)是javac -proc:only -processor com.foo.bar.MyProcessor MyProject/src/*第二遍(常规构建)是javac MyProject/src/*如果您使用的是 Ant 或 Maven 之类的东西,您应该能够更新构建指令,只需最少的工作量即可获得两次编译器传递。编辑:这是我对 Gradle 说明的尝试我没有使用 Gradle 的经验,但看起来你需要做这样的事情。在您的 Gradle 构建脚本中,您需要定义预处理任务并将对您的任务的依赖项添加到 javaCompile 任务。javaCompile.dependsOn myAnnotationTasktask myAnnotationTask(type: JavaCompile) {&nbsp; &nbsp; options.compilerArgs << '-proc:only' << '-processors com.foo.bar.MyAnnotationProcessor'}
随时随地看视频慕课网APP

相关分类

Java
我要回答