1. 简介

本文将介绍 KotlinPoet,一个用于生成 Kotlin 源代码的开源库。我们会了解它的基本用途、能生成的代码类型,以及如何在项目中使用它。

KotlinPoet 是 Square 公司开发的 JavaPoet 的 Kotlin 版本。如果你熟悉 JavaPoet,那么 KotlinPoet 的使用方式会非常类似。

2. KotlinPoet 是什么?

KotlinPoet 是一个用于生成 Kotlin 源码的库,由 Square 维护。它与 JavaPoet 类似,但专注于 Kotlin。

不同于 ASM 这类直接操作字节码的工具,KotlinPoet 生成的是原始的、未编译的 Kotlin 源码。这意味着生成的代码需要先编译,才能运行。但在某些场景下,这种机制反而更灵活,比如构建时代码生成、IDE 插件开发等。

它可以生成 Kotlin 中常见的各种结构:类、函数、属性、注解等。这意味着你可以用它来生成一行代码,也可以生成整个 Kotlin 文件。

3. 依赖配置

使用 KotlinPoet 前,需要在项目中引入依赖。截至本文撰写时,最新版本为 1.16.0

Maven 配置:

<dependency>
    <groupId>com.squareup</groupId>
    <artifactId>kotlinpoet-jvm</artifactId>
    <version>1.16.0</version>
</dependency>

Gradle 配置:

implementation("com.squareup:kotlinpoet:1.16.0")

引入依赖后即可开始使用 KotlinPoet。

4. 生成代码的基本方式

KotlinPoet 通过一系列 Spec 类来生成代码。每个 Spec 对应一种代码结构:

  • TypeSpec:类、接口、对象等类型定义
  • FunSpec:函数定义
  • PropertySpec:属性定义
  • FileSpec:整个 Kotlin 文件

这些类都提供了 builder 模式用于构建代码结构。

例如,生成一个空类:

val code = TypeSpec.classBuilder("Test").build()

生成的代码如下:

public class Test

调用 toString() 即可获取生成的代码字符串。

5. 生成函数

生成函数是 KotlinPoet 的核心功能之一。可以生成函数签名、参数、返回值和函数体。

使用 FunSpec 构建函数:

FunSpec.builder("simple") // public fun simple() {}
FunSpec.constructorBuilder() // public constructor()
FunSpec.getterBuilder() // public get() {}
FunSpec.setterBuilder() // public set() {}

5.1. 函数体的构建

函数体使用 addStatement() 添加:

val code = FunSpec.builder("test")
  .addStatement("println(\"Testing\")")
  .build()

生成代码如下:

public fun test() {
    println("Testing")
}

你也可以使用格式化字符串简化字符串拼接:

val code = FunSpec.builder("test")
  .addStatement("println(%S)", "Testing")
  .build()

常用格式化参数说明:

格式符 含义
%S 字符串,自动加引号并转义
%P 字符串模板,加引号但不转义 $
%L 字面量,直接插入
%N 其他代码元素,插入其名称
%T 类型,自动导入并插入
%M 包/类成员,自动处理引用和导入

5.2. 控制流结构

生成 if、for 等控制结构时,使用 beginControlFlow()endControlFlow()

val code = FunSpec.builder("test")
  .beginControlFlow("if (showOutput)")
  .addStatement("println(%S)", "Testing")
  .endControlFlow()
  .build()

生成代码如下:

public fun test() {
    if (showOutput) {
        println("Testing")
    }
}

你还可以使用 nextControlFlow() 来添加 else ifelse 分支。

5.3. 参数设置

使用 addParameter() 添加函数参数:

val code = FunSpec.builder("test")
  .addParameter("param", String::class)
  .build()

生成:

public fun test(param: kotlin.String) {
}

你也可以为参数指定默认值:

.addParameter(ParameterSpec.builder("param", Int::class).defaultValue("%L", 42).build())

5.4. 返回值类型

使用 returns() 设置返回类型:

val code = FunSpec.builder("test")
  .returns(String::class)
  .build()

生成:

public fun test(): kotlin.String {
}

如果函数只有一行 return 语句,KotlinPoet 会自动使用单表达式函数语法:

.addStatement("return 5")
.returns(Int::class)

生成:

public fun test(): kotlin.Int = 5

6. 生成类型定义

除了函数,KotlinPoet 也支持生成类、接口、对象、枚举等类型。

使用 TypeSpec 构建类型:

TypeSpec.classBuilder("Test") // public class Test
TypeSpec.interfaceBuilder("Test") // public interface Test
TypeSpec.objectBuilder("Test") // public object Test
TypeSpec.enumBuilder("Test") // public enum class Test

6.1. 添加方法

使用 addFunction() 向类中添加方法:

val code = TypeSpec.classBuilder("Test")
  .addFunction(FunSpec.builder("doSomething")
    .returns(Int::class)
    .addParameter("input", String::class)
    .build())
  .build()

生成:

public class Test {
    public fun doSomething(input: kotlin.String): kotlin.Int {
    }
}

6.2. 设置访问修饰符

使用 addModifiers() 设置访问修饰符或其它修饰符(如 abstractfinal):

.addFunction(FunSpec.builder("doSomething")
  .addModifiers(KModifier.PROTECTED, KModifier.ABSTRACT)
  .build())

⚠️ 注意:KotlinPoet 不会阻止你设置逻辑冲突的修饰符组合,比如 finalabstract 同时存在。这类逻辑错误需开发者自行注意。

6.3. 添加属性

使用 PropertySpec 添加类属性:

.addProperty(PropertySpec.builder("test", String::class)
  .addModifiers(KModifier.PRIVATE)
  .mutable()
  .initializer("%S", "Hello")
  .build())

生成:

private var test: kotlin.String = "Hello"

也可以简化为:

.addProperty("test", String::class)

7. 生成完整 Kotlin 文件

最后,我们来看看如何生成一个完整的 .kt 文件。

使用 FileSpec 构建文件:

val code = FileSpec.builder("com.baeldung.kotlin.kotlinpoet", "Testing.kt").build()

生成:

package com.baeldung.kotlin.kotlinpoet

你可以继续添加类、函数、属性等:

val code = FileSpec.builder("com.baeldung.kotlin.kotlinpoet", "Testing.kt")
  .addType(TypeSpec.classBuilder("Testing")
    .addFunction(FunSpec.builder("count")
      .returns(Int::class)
      .addParameter(ParameterSpec.builder("items", List::class).build())
      .addStatement("return items.size()")
      .build())
    .build())
  .build()

生成:

package com.baeldung.kotlin.kotlinpoet

import kotlin.Int
import kotlin.collections.List

public class Testing {
    public fun count(items: List): Int = items.size()
}

KotlinPoet 会自动添加必要的 import 语句,并省略全限定类名。

8. 总结

KotlinPoet 是一个功能强大、使用灵活的代码生成工具。它可以帮助你自动化生成 Kotlin 代码,适用于构建插件、代码模板生成、DSL 构建等场景。

虽然本文只介绍了它的基础用法,但它的能力远不止这些。建议你尝试在自己的项目中集成并使用它。

所有示例代码都可以在 GitHub 上找到:GitHub 示例地址


原始标题:Introduction to KotlinPoet