kapt 编译器插件
DANGER
kapt 处于维护模式。我们正使其与最新的 Kotlin 和 Java 版本保持同步,但没有计划实现新功能。请使用 Kotlin 符号处理 API (KSP) 进行注解处理。
Kotlin 通过 kapt 编译器插件支持注解处理器(请参阅 JSR 269)。
简而言之,你可以在 Kotlin 项目中使用 Dagger 或 Data Binding 等库。
请阅读下文,了解如何将 kapt 插件应用于你的 Gradle/Maven 构建。
在 Gradle 中使用
请按照以下步骤操作:
应用
kotlin-kapt
Gradle 插件:
plugins {
kotlin("kapt") version "2.1.21"
}
plugins {
id "org.jetbrains.kotlin.kapt" version "2.1.21"
}
:::
在
dependencies
代码块中使用kapt
配置添加相应的依赖项:
dependencies {
kapt("groupId:artifactId:version")
}
dependencies {
kapt 'groupId:artifactId:version'
}
:::
如果你之前使用 Android 支持进行注解处理,请将
annotationProcessor
配置的用法替换为kapt
。 如果你的项目包含 Java 类,kapt
也会处理它们。如果你将注解处理器用于
androidTest
或test
源,相应的kapt
配置名称为kaptAndroidTest
和kaptTest
。请注意,kaptAndroidTest
和kaptTest
扩展了kapt
,因此你只需提供kapt
依赖项,它将同时适用于生产源和测试。
试用 Kotlin K2 编译器
DANGER
kapt 编译器插件对 K2 的支持是实验性的 (Experimental)。需要选择启用(详情见下文),且你应仅将其用于评估目的。
从 Kotlin 1.9.20 开始,你可以尝试将 kapt 编译器插件与 K2 编译器一起使用,它带来了性能改进和许多其他优势。要在 Gradle 项目中使用 K2 编译器,请将以下选项添加到 gradle.properties
文件中:
kapt.use.k2=true
如果你使用 Maven 构建系统,请更新 pom.xml
文件:
<configuration>
...
<args>
<arg>-Xuse-k2-kapt</arg>
</args>
</configuration>
如果在将 kapt 与 K2 编译器一起使用时遇到任何问题,请向我们的问题追踪器报告。
注解处理器参数
使用 arguments {}
代码块将参数传递给注解处理器:
kapt {
arguments {
arg("key", "value")
}
}
Gradle 构建缓存支持
kapt 注解处理任务在 Gradle 中默认是缓存的。 然而,注解处理器会运行任意代码,这些代码可能不一定会将任务输入转换为输出,可能会访问和修改 Gradle 未跟踪的文件等。如果构建中使用的注解处理器无法正确缓存,可以通过在构建脚本中添加以下行来完全禁用 kapt 的缓存,以避免 kapt 任务的假阳性缓存命中:
kapt {
useBuildCache = false
}
提高使用 kapt 的构建速度
并行运行 kapt 任务
为了提高使用 kapt 的构建速度,你可以为 kapt 任务启用 Gradle Worker API。使用 Worker API 允许 Gradle 并行运行单个项目中的独立注解处理任务,这在某些情况下可以显著缩短执行时间。
当你在 Kotlin Gradle 插件中使用自定义 JDK 主目录功能时,kapt 任务 worker 仅使用进程隔离模式。 请注意,kapt.workers.isolation
属性将被忽略。
如果你想为 kapt worker 进程提供额外的 JVM 参数,请使用 KaptWithoutKotlincTask
的输入 kaptProcessJvmArgs
:
tasks.withType<org.jetbrains.kotlin.gradle.internal.KaptWithoutKotlincTask>()
.configureEach {
kaptProcessJvmArgs.add("-Xmx512m")
}
tasks.withType(org.jetbrains.kotlin.gradle.internal.KaptWithoutKotlincTask.class)
.configureEach {
kaptProcessJvmArgs.add('-Xmx512m')
}
注解处理器类加载器缓存
注解处理器类加载器缓存有助于在你连续运行多个 Gradle 任务时,使 kapt 执行得更快。
要启用此功能,请在 gradle.properties
文件中使用以下属性:
# positive value will enable caching
# use the same value as the number of modules that use kapt
kapt.classloaders.cache.size=5
# disable for caching to work
kapt.include.compile.classpath=false
如果你在使用注解处理器缓存时遇到任何问题,请禁用它们的缓存:
# specify annotation processors' full names to disable caching for them
kapt.classloaders.cache.disableForProcessors=[annotation processors full names]
衡量注解处理器性能
使用 -Kapt-show-processor-timings
插件选项获取注解处理器执行的性能统计信息。 示例输出:
Kapt Annotation Processing performance report:
com.example.processor.TestingProcessor: total: 133 ms, init: 36 ms, 2 round(s): 97 ms, 0 ms
com.example.processor.AnotherProcessor: total: 100 ms, init: 6 ms, 1 round(s): 93 ms
你可以使用插件选项 -Kapt-dump-processor-timings
(org.jetbrains.kotlin.kapt3:dumpProcessorTimings
) 将此报告转储到文件中。 以下命令将运行 kapt 并将统计信息转储到 ap-perf-report.file
文件中:
kotlinc -cp $MY_CLASSPATH \
-Xplugin=kotlin-annotation-processing-SNAPSHOT.jar -P \
plugin:org.jetbrains.kotlin.kapt3:aptMode=stubsAndApt,\
plugin:org.jetbrains.kotlin.kapt3:apclasspath=processor/build/libs/processor.jar,\
plugin:org.jetbrains.kotlin.kapt3:dumpProcessorTimings=ap-perf-report.file \
-Xplugin=$JAVA_HOME/lib/tools.jar \
-d cli-tests/out \
-no-jdk -no-reflect -no-stdlib -verbose \
sample/src/main/
衡量注解处理器生成的文件数量
kotlin-kapt
Gradle 插件可以报告每个注解处理器生成文件数量的统计信息。
这对于跟踪构建中是否存在未使用的注解处理器非常有用。 你可以使用生成的报告来查找触发不必要注解处理器的模块,并更新这些模块以防止这种情况发生。
分两步启用统计信息:
在
build.gradle(.kts)
中将showProcessorStats
标志设置为true
:kotlinkapt { showProcessorStats = true }
在
gradle.properties
中将kapt.verbose
Gradle 属性设置为true
:nonekapt.verbose=true
NOTE
你也可以通过命令行选项 verbose
启用详细输出。
统计信息将以 info
级别出现在日志中。你将看到 Annotation processor stats:
行,其后是每个注解处理器执行时间的统计信息。这些行之后,将有 Generated files report:
行,其后是每个注解处理器生成文件数量的统计信息。例如:
[INFO] Annotation processor stats:
[INFO] org.mapstruct.ap.MappingProcessor: total: 290 ms, init: 1 ms, 3 round(s): 289 ms, 0 ms, 0 ms
[INFO] Generated files report:
[INFO] org.mapstruct.ap.MappingProcessor: total sources: 2, sources per round: 2, 0, 0
kapt 的编译规避
为了缩短使用 kapt 的增量构建时间,它可以使用 Gradle 的编译规避。 启用编译规避后,Gradle 可以在重建项目时跳过注解处理。特别是,在以下情况下会跳过注解处理:
- 项目的源文件未更改。
- 依赖项中的更改与 ABI 兼容。 例如,唯一的更改是在方法体中。
然而,对于在编译类路径中发现的注解处理器,不能使用编译规避,因为它们的_任何更改_都需要运行注解处理任务。
要使用编译规避运行 kapt:
- 如上文所述,手动将注解处理器依赖项添加到
kapt*
配置中。 - 通过在
gradle.properties
文件中添加此行,关闭编译类路径中注解处理器的发现:
kapt.include.compile.classpath=false
增量注解处理
kapt 支持增量注解处理,此功能默认启用。 目前,只有当所有使用的注解处理器都是增量式时,注解处理才能是增量式的。
要禁用增量注解处理,请在 gradle.properties
文件中添加此行:
kapt.incremental.apt=false
请注意,增量注解处理也要求增量编译启用。
从父配置继承注解处理器
你可以在单独的 Gradle 配置中定义一组公共的注解处理器作为父配置,并在子项目的 kapt 特定配置中进一步扩展它。
例如,对于使用 Dagger 的子项目,在 build.gradle(.kts)
文件中使用以下配置:
val commonAnnotationProcessors by configurations.creating
configurations.named("kapt") { extendsFrom(commonAnnotationProcessors) }
dependencies {
implementation("com.google.dagger:dagger:2.48.1")
commonAnnotationProcessors("com.google.dagger:dagger-compiler:2.48.1")
}
在此示例中,commonAnnotationProcessors
Gradle 配置是你希望所有项目都使用的注解处理的公共父配置。你使用 extendsFrom()
方法将 commonAnnotationProcessors
添加为父配置。kapt 会看到 commonAnnotationProcessors
Gradle 配置依赖于 Dagger 注解处理器。因此,kapt 将 Dagger 注解处理器包含在其注解处理配置中。
Java 编译器选项
kapt 使用 Java 编译器来运行注解处理器。 以下是如何将任意选项传递给 javac:
kapt {
javacOptions {
// Increase the max count of errors from annotation processors.
// Default is 100.
option("-Xmaxerrs", 500)
}
}
不存在类型修正
一些注解处理器(如 AutoFactory
)依赖于声明签名中的精确类型。 默认情况下,kapt 会将所有未知类型(包括生成类的类型)替换为 NonExistentClass
,但你可以更改此行为。在 build.gradle(.kts)
文件中添加该选项以在存根中启用错误类型推断:
kapt {
correctErrorTypes = true
}
在 Maven 中使用
在 compile
之前添加 kotlin-maven-plugin 的 kapt
目标执行:
<execution>
<id>kapt</id>
<goals>
<goal>kapt</goal> <!-- You can skip the <goals> element
if you enable extensions for the plugin -->
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/main/kotlin</sourceDir>
<sourceDir>src/main/java</sourceDir>
</sourceDirs>
<annotationProcessorPaths>
<!-- Specify your annotation processors here -->
<annotationProcessorPath>
<groupId>com.google.dagger</groupId>
<artifactId>dagger-compiler</artifactId>
<version>2.9</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</execution>
要配置注解处理级别,请在 <configuration>
代码块中将 aptMode
设置为以下之一:
stubs
– 仅生成注解处理所需的存根。apt
– 仅运行注解处理。stubsAndApt
– (默认) 生成存根并运行注解处理。
例如:
<configuration>
...
<aptMode>stubs</aptMode>
</configuration>
要使用 K2 编译器启用 kapt 插件,请添加 -Xuse-k2-kapt
编译器选项:
<configuration>
...
<args>
<arg>-Xuse-k2-kapt</arg>
</args>
</configuration>
在 IntelliJ 构建系统中使用
IntelliJ IDEA 自己的构建系统不支持 kapt。每当你想要重新运行注解处理时,请从“Maven Projects”工具栏启动构建。
在 CLI 中使用
kapt 编译器插件在 Kotlin 编译器的二进制发行版中可用。
你可以通过使用 Xplugin
kotlinc 选项提供其 JAR 文件的路径来附加插件:
-Xplugin=$KOTLIN_HOME/lib/kotlin-annotation-processing.jar
以下是可用选项列表:
sources
(必填): 生成文件的输出路径。classes
(必填): 生成的类文件和资源的输出路径。stubs
(必填): 存根文件的输出路径。换句话说,一个临时目录。incrementalData
: 二进制存根的输出路径。apclasspath
(可重复): 注解处理器 JAR 的路径。根据你的 JAR 数量传递相同数量的apclasspath
选项。apoptions
: base64 编码的注解处理器选项列表。更多信息请参阅 AP/javac 选项编码。javacArguments
: base64 编码的传递给 javac 的选项列表。更多信息请参阅 AP/javac 选项编码。processors
: 逗号分隔的注解处理器完全限定类名列表。如果指定,kapt 不会尝试在apclasspath
中查找注解处理器。verbose
: 启用详细输出。aptMode
(必填)stubs
– 仅生成注解处理所需的存根。apt
– 仅运行注解处理。stubsAndApt
– 生成存根并运行注解处理。
correctErrorTypes
: 更多信息请参阅 不存在类型修正。默认禁用。dumpFileReadHistory
: 用于为每个文件转储注解处理期间使用的类列表的输出路径。
插件选项格式为:-P plugin:<plugin id>:<key>=<value>
。选项可以重复。
示例:
-P plugin:org.jetbrains.kotlin.kapt3:sources=build/kapt/sources
-P plugin:org.jetbrains.kotlin.kapt3:classes=build/kapt/classes
-P plugin:org.jetbrains.kotlin.kapt3:stubs=build/kapt/stubs
-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=lib/ap.jar
-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=lib/anotherAp.jar
-P plugin:org.jetbrains.kotlin.kapt3:correctErrorTypes=true
生成 Kotlin 源文件
kapt 可以生成 Kotlin 源文件。只需将生成的 Kotlin 源文件写入 processingEnv.options["kapt.kotlin.generated"]
指定的目录,这些文件将与主源文件一起编译。
请注意,kapt 不支持对生成的 Kotlin 文件进行多轮处理。
AP/Javac 选项编码
apoptions
和 javacArguments
CLI 选项接受编码的选项映射。 以下是你如何自行编码选项:
fun encodeList(options: Map<String, String>): String {
val os = ByteArrayOutputStream()
val oos = ObjectOutputStream(os)
oos.writeInt(options.size)
for ((key, value) in options.entries) {
oos.writeUTF(key)
oos.writeUTF(value)
}
oos.flush()
return Base64.getEncoder().encodeToString(os.toByteArray())
}
保留 Java 编译器的注解处理器
默认情况下,kapt 会运行所有注解处理器并禁用 javac 的注解处理。 但是,你可能需要一些 javac 的注解处理器工作(例如 Lombok)。
在 Gradle 构建文件中,使用 keepJavacAnnotationProcessors
选项:
kapt {
keepJavacAnnotationProcessors = true
}
如果你使用 Maven,你需要指定具体的插件设置。 请参阅此关于 Lombok 编译器插件的设置示例。