Skip to content

kapt 编译器插件

  • 在以下情况下使用 kapt
    • 你使用的是 Maven 项目。
    • 你使用的是 Gradle 项目,但所需的 Java 注解处理器尚不支持 KSP。查看支持的库列表
  • 在以下情况下使用 KSP
    • 你使用的是 Gradle 项目,且所需的 Java 注解处理器支持 KSP。
    • 你想要创建自己的注解处理器。

kapt 编译器插件允许你在 Kotlin 中使用现有的 Java 注解处理器,并同时支持 Maven 和 Gradle。 它从 Kotlin 源代码生成存根文件,然后在这些存根上运行 Java 注解处理器。

这使得在你的 Kotlin 项目中可以为 MapStruct数据绑定 等库启用基于 Java 的注解处理。

在 Gradle 中使用

要在 Gradle 中使用 kapt,请按照以下步骤操作:

  1. 在你的构建脚本文件 build.gradle(.kts) 中应用 kapt Gradle 插件:

    kotlin
    plugins {
        kotlin("kapt") version "2.3.0"
    }
    groovy
    plugins {
        id "org.jetbrains.kotlin.kapt" version "2.3.0"
    }
  2. dependencies {} 代码块中使用 kapt 配置添加相应的依赖项:

    kotlin
    dependencies {
        kapt("groupId:artifactId:version")
    }
    groovy
    dependencies {
        kapt 'groupId:artifactId:version'
    }
  3. 如果你之前使用 Android 支持 来处理注解处理器,请将 annotationProcessor 配置的用法替换为 kapt。如果你的项目包含 Java 类,kapt 也会负责处理它们。

    如果你为 androidTesttest 源码使用注解处理器,相应的 kapt 配置分别命名为 kaptAndroidTestkaptTest。注意 kaptAndroidTestkaptTest 继承自 kapt,因此你可以提供 kapt 依赖项,它将同时用于生产源码和测试。

注解处理器参数

在你的构建脚本文件 build.gradle(.kts) 中使用 arguments {} 代码块向注解处理器传递参数:

kotlin
kapt {
    arguments {
        arg("key", "value")
    }
}

Gradle 构建缓存支持

kapt 注解处理任务默认在 Gradle 中缓存。 然而,注解处理器可以运行任意代码,这些代码可能无法可靠地将任务输入转换为输出,或者可能会访问和修改 Gradle 无法跟踪的文件。 如果构建中使用的注解处理器无法被正确缓存,你可以通过在构建脚本中指定 useBuildCache 属性来完全禁用 kapt 的缓存。 这有助于防止 kapt 任务出现误报的缓存命中:

groovy
kapt {
    useBuildCache = false
}

提高使用 kapt 的构建速度

并行运行 kapt 任务

为了提高使用 kapt 的构建速度,你可以为 kapt 任务启用 Gradle Worker API。使用 Worker API 让 Gradle 能够并行运行来自单个项目的独立注解处理任务,在某些情况下,这会显著减少执行时间。

当你在 Kotlin Gradle 插件中使用 自定义 JDK 路径 功能时,kapt 任务工作程序仅使用 进程隔离模式。请注意,kapt.workers.isolation 属性会被忽略。

如果你想为 kapt 工作进程提供额外的 JVM 参数,请使用 KaptWithoutKotlincTask 的输入 kaptProcessJvmArgs

kotlin
tasks.withType<org.jetbrains.kotlin.gradle.internal.KaptWithoutKotlincTask>()
    .configureEach {
        kaptProcessJvmArgs.add("-Xmx512m")
    }
groovy
tasks.withType(org.jetbrains.kotlin.gradle.internal.KaptWithoutKotlincTask.class)
    .configureEach {
        kaptProcessJvmArgs.add('-Xmx512m')
    }
Experimental

为注解处理器的类加载器启用缓存

如果你连续运行多个 Gradle 任务,为注解处理器的类加载器启用缓存有助于 kapt 运行得更快。

要启用此功能,请在你的 gradle.properties 文件中使用以下属性:

none
# gradle.properties
#
# 任何正值都会启用缓存
# 使用与使用 kapt 的模块数量相同的值
kapt.classloaders.cache.size=5

# 禁用此项以使缓存工作
kapt.include.compile.classpath=false

如果你在注解处理器的缓存方面遇到任何问题,请为它们禁用缓存:

none
# 指定注解处理器的全名以禁用它们的缓存
kapt.classloaders.cache.disableForProcessors=[annotation processors full names]

如果你遇到该功能的任何问题,我们非常感谢你在 YouTrack 中提供反馈。

衡量注解处理器的性能

要获取有关注解处理器执行情况的性能统计信息,请使用 -Kapt-show-processor-timings 插件选项。示例输出如下:

text
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 文件中:

bash
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/

统计使用注解处理器生成的文件数量

kapt Gradle 插件可以报告每个注解处理器生成文件数量的统计信息。

这有助于跟踪构建中是否包含任何未使用的注解处理器。你可以使用生成的报告找到触发不必要注解处理器的模块,并更新这些模块以避免这种情况。

要启用统计报告:

  1. 在你的 build.gradle(.kts) 中将 showProcessorStats 属性值设置为 true

    kotlin
    // build.gradle.kts
    kapt {
        showProcessorStats = true
    }
  2. 在你的 gradle.properties 中将 kapt.verbose Gradle 属性设置为 true

    none
    # gradle.properties
    kapt.verbose=true

你也可以通过 命令行选项 verbose 来启用详细输出。

统计信息以 info 级别出现在日志中。你可以看到 Annotation processor stats: 行,随后是每个注解处理器执行时间的统计信息。在这些行之后是 Generated files report: 行,随后是每个注解处理器生成文件数量的统计信息。例如:

text
[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 文件中添加这一行:

none
kapt.incremental.apt=false

请注意,增量注解处理还要求同时启用 增量编译

从超配置中继承注解处理器

你可以在一个单独的 Gradle 配置中定义一组通用的注解处理器作为超配置,并在子项目中专门针对 kapt 的配置进一步扩展它。

例如,对于使用 MapStruct 的子项目,在你的 build.gradle(.kts) 文件中使用以下配置:

kotlin
val commonAnnotationProcessors by configurations.creating
configurations.named("kapt") { extendsFrom(commonAnnotationProcessors) }

dependencies {
    implementation("org.mapstruct:mapstruct:1.6.3")
    commonAnnotationProcessors("org.mapstruct:mapstruct-processor:1.6.3")
}

在此示例中,commonAnnotationProcessors Gradle 配置是你希望在所有项目中使用的通用注解处理超配置。你使用 extendsFrom() 方法将 commonAnnotationProcessors 添加为超配置。kapt 识别到 commonAnnotationProcessors Gradle 配置对 MapStruct 注解处理器有依赖。因此,kapt 在其注解处理配置中包含了 MapStruct 注解处理器。

Java 编译器选项

kapt 使用 Java 编译器来运行注解处理器。 以下是向 javac 传递任意选项的方法:

groovy
kapt {
    javacOptions {
        // 增加来自注解处理器的最大错误计数。
        // 默认为 100。
        option("-Xmaxerrs", 500)
    }
}

不存在的类型修正

某些注解处理器(如 AutoFactory)依赖于声明签名中的精确类型。 默认情况下,kapt 会将每个未知类型(包括生成的类的类型)替换为 NonExistentClass,但你可以更改此行为。在 build.gradle(.kts) 文件中添加该选项,以启用在存根中的错误类型推断:

groovy
kapt {
    correctErrorTypes = true
}

在 Maven 中使用

compile 之前添加 kotlin-maven-plugin 中 kapt 目标的执行:

xml
<execution>
    <id>kapt</id>
    <goals>
        <goal>kapt</goal> <!-- 如果你为该插件启用了扩展,
        可以跳过 <goals> 元素 -->
    </goals>
    <configuration>
        <sourceDirs>
            <sourceDir>src/main/kotlin</sourceDir>
            <sourceDir>src/main/java</sourceDir>
        </sourceDirs>
        <annotationProcessorPaths>
            <!-- 在此处指定你的注解处理器 -->
            <annotationProcessorPath>
                <groupId>org.mapstruct</groupId>
                <artifactId>mapstruct-processor</artifactId>
                <version>1.6.3</version>
            </annotationProcessorPath>
        </annotationProcessorPaths>
    </configuration>
</execution>

要配置注解处理的级别,请在 <configuration> 代码块中将以下内容之一设置为 aptMode

  • stubs – 仅生成注解处理所需的存根。
  • apt – 仅运行注解处理。
  • stubsAndApt – (默认)生成存根并运行注解处理。

例如:

xml
<configuration>
   ...
   <aptMode>stubs</aptMode>
</configuration>

在 IntelliJ 构建系统中使用

IntelliJ IDEA 的自有构建系统不支持 kapt。每当你想要重新运行注解处理时,请从“Maven Projects”工具栏启动构建。

在命令行中使用

kapt 编译器插件在 Kotlin 编译器的二进制分发版中可用。

你可以通过使用 kotlinc 选项 Xplugin 提供其 JAR 文件的路径来附加该插件:

bash
-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>。选项可以重复。

示例:

bash
-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 选项编码

apoptionsjavacArguments 命令行选项接受一个编码后的选项映射。 以下是你可以自行编码选项的方法:

kotlin
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

groovy
kapt {
    keepJavacAnnotationProcessors = true
}

如果你使用 Maven,则需要显式配置该插件。 参见这个 Lombok 编译器插件设置示例

下一步