KotlinFile 是 CodeGentle 库中用于表示和生成 Kotlin 源文件的核心接口。它支持包含顶层类、接口、对象、函数、属性以及脚本代码的完整 Kotlin 文件生成。
KotlinFile 接口继承自 KotlinCodeEmitter 和 Named,提供了 Kotlin 文件的完整抽象。
| 属性 | 类型 | 说明 |
|---|---|---|
fileComment |
CodeValue |
文件顶部注释 |
packageName |
PackageName |
包名 |
name |
String |
文件名(不含扩展名) |
types |
List<KotlinTypeSpec> |
顶层类型列表(类、接口、对象等) |
functions |
List<KotlinFunctionSpec> |
顶层函数列表 |
properties |
List<KotlinPropertySpec> |
顶层属性列表 |
type |
KotlinTypeSpec |
第一个类型(兼容性属性,等同于 types.first()) |
staticImports |
Set<String> |
静态导入集合 |
alwaysQualify |
Set<String> |
始终使用全限定名的类型集合 |
indent |
String |
缩进字符串(默认为四个空格) |
annotations |
List<AnnotationRef> |
文件级注解列表(使用 @file: 语法) |
fun writeTo(out: Appendable, strategy: KotlinWriteStrategy)将 Kotlin 文件写入到指定的 Appendable 输出目标。
参数:
out: 输出目标(如StringBuilder、Writer等)strategy: 写入策略,控制代码生成的行为
KotlinFileBuilder 是构建 KotlinFile 实例的抽象基类,提供了两种具体实现:
用于构建普通 Kotlin 文件(.kt),包含类、接口、函数、属性等顶层元素。
用于构建 Kotlin 脚本文件(.kts),除了支持顶层元素外,还支持直接编写脚本代码。
创建包含单个类型的文件构建器:
val file = KotlinFile.builder(
packageName = "com.example".parseToPackageName(),
type = KotlinSimpleTypeSpec(KotlinTypeSpec.Kind.CLASS, "MyClass")
).build()创建空文件构建器,稍后添加元素:
val file = KotlinFile.builder("com.example".parseToPackageName())
.addType(typeSpec)
.addFunction(functionSpec)
.addProperty(propertySpec)
.build()创建脚本文件构建器:
val scriptFile = KotlinFile.scriptBuilder()
.addCode("println(\"Hello, World!\")")
.build()// 单个类型
val file = KotlinFile("com.example", typeSpec) {
addFileComment("This is a generated file")
addStaticImport("kotlin.collections.Collections", "emptyList")
}
// 多个类型(vararg)
val file = KotlinFile("com.example", typeSpec1, typeSpec2) {
indent("\t")
}
// 多个类型(Iterable)
val types = listOf(typeSpec1, typeSpec2)
val file = KotlinFile("com.example", types) {
name("CustomFileName")
}
// 仅函数和属性
val file = KotlinFile("com.example".parseToPackageName()) {
addFunction(functionSpec)
addProperty(propertySpec)
}val scriptFile = KotlinFile {
addStatement("val x = 10")
addStatement("println(x)")
addFunction(helperFunction)
}// 添加单个类型
fun addType(type: KotlinTypeSpec): B
// 添加多个类型(Iterable)
fun addTypes(types: Iterable<KotlinTypeSpec>): B
// 添加多个类型(vararg)
fun addTypes(vararg types: KotlinTypeSpec): B// 添加单个函数
fun addFunction(function: KotlinFunctionSpec): B
// 添加多个函数
fun addFunctions(functions: Iterable<KotlinFunctionSpec>): B// 添加单个属性
fun addProperty(property: KotlinPropertySpec): B
// 添加多个属性
fun addProperties(properties: Iterable<KotlinPropertySpec>): B// 简单格式
fun addFileComment(format: String): B
// 带代码块
fun addFileComment(format: String, block: CodeValueSingleFormatBuilderDsl): B
// 使用 CodeValue
fun addFileComment(codeValue: CodeValue): B示例:
KotlinFile("com.example", typeSpec) {
addFileComment("Copyright (C) 2025 Example Corp")
addFileComment("Generated at: %L", block = {
add(System.currentTimeMillis())
})
}// 导入字符串
fun addStaticImport(import: String): B
// 导入类成员(vararg)
fun addStaticImport(className: ClassName, vararg names: String): B
// 导入类成员(Iterable)
fun addStaticImport(className: ClassName, names: Iterable<String>): B示例:
KotlinFile("com.example", typeSpec) {
addStaticImport("kotlin.io.println")
addStaticImport(
ClassName("kotlin.collections", "Collections"),
"emptyList", "emptyMap"
)
}文件级注解使用 @file: 语法,必须设置正确的 useSite:
// 添加单个注解
fun addAnnotation(ref: AnnotationRef): B
// 添加多个注解
fun addAnnotations(refs: Iterable<AnnotationRef>): B示例:
val suppressAnnotation = ClassName("kotlin", "Suppress").kotlinAnnotationRef {
addMember("\"UNUSED\"")
status {
useSite = KotlinAnnotationUseSite.FILE
}
}
KotlinFile("com.example", typeSpec) {
addAnnotation(suppressAnnotation)
}生成代码:
@file:Suppress("UNUSED")
package com.example
class MyClass注意事项:
- 只能添加
useSite = FILE或未指定useSite的注解 - 其他
useSite(如FIELD、GET等)会抛出IllegalArgumentException - 注解会在
package声明之前生成
// 设置缩进(默认四个空格)
fun indent(indent: String): B
// 设置文件名
fun name(name: String): Bfun build(): KotlinFile这些扩展函数简化了特定类型的创建:
// 添加类
fun <B : KotlinFileBuilder<B>> B.addSimpleClassType(
name: String,
block: KotlinSimpleTypeSpec.Builder.() -> Unit = {}
): B
// 添加接口
fun <B : KotlinFileBuilder<B>> B.addSimpleInterfaceType(
name: String,
block: KotlinSimpleTypeSpec.Builder.() -> Unit = {}
): B示例:
KotlinFile("com.example") {
addSimpleClassType("Person") {
addModifier(KotlinModifier.DATA)
addProperty(nameProperty)
}
addSimpleInterfaceType("Drawable") {
addFunction(drawFunction)
}
}fun <B : KotlinFileBuilder<B>> B.addObjectType(
name: String,
isCompanion: Boolean = false,
block: KotlinObjectTypeSpec.Builder.() -> Unit = {}
): B示例:
KotlinFile("com.example") {
addObjectType("Singleton") {
addProperty(instanceProperty)
}
}fun <B : KotlinFileBuilder<B>> B.addEnumType(
name: String,
block: KotlinEnumTypeSpec.Builder.() -> Unit = {}
): B示例:
KotlinFile("com.example") {
addEnumType("Color") {
addEnumConstant("RED")
addEnumConstant("GREEN")
addEnumConstant("BLUE")
}
}fun <B : KotlinFileBuilder<B>> B.addAnnotationType(
name: String,
block: KotlinAnnotationTypeSpec.Builder.() -> Unit = {}
): B示例:
KotlinFile("com.example") {
addAnnotationType("MyAnnotation") {
addProperty(valueProperty)
}
}// 使用 KotlinConstructorSpec
fun <B : KotlinFileBuilder<B>> B.addValueClassType(
name: String,
primaryConstructor: KotlinConstructorSpec,
block: KotlinValueClassTypeSpec.Builder.() -> Unit = {}
): B
// 使用构造器 DSL
fun <B : KotlinFileBuilder<B>> B.addValueClassType(
name: String,
primaryConstructor: KotlinConstructorSpec.Builder.() -> Unit,
block: KotlinValueClassTypeSpec.Builder.() -> Unit = {}
): B
// 使用单个参数
fun <B : KotlinFileBuilder<B>> B.addValueClassType(
name: String,
primaryParameter: KotlinValueParameterSpec,
block: KotlinValueClassTypeSpec.Builder.() -> Unit = {}
): B示例:
KotlinFile("com.example") {
addValueClassType("UserId", primaryParameter = KotlinValueParameterSpec(
name = "value",
type = ClassName("kotlin", "String").ref()
) {
immutableProperty()
})
}fun <B : KotlinFileBuilder<B>> B.addTypealiasType(
name: String,
type: TypeRef<*>,
block: KotlinTypealiasSpec.Builder.() -> Unit = {}
): B示例:
KotlinFile("com.example") {
addTypealiasType(
name = "StringMap",
type = ClassName("kotlin.collections", "Map")
.parameterizedBy(stringRef, stringRef)
.ref()
)
}将 KotlinFile 转换为相对路径字符串,用于文件系统操作。
fun KotlinFile.toRelativePath(
filename: String = this.name,
isScript: Boolean = false,
separator: String = "/"
): String参数:
filename: 文件名(默认使用this.name)isScript: 是否为脚本文件(.ktsvs.kt)separator: 路径分隔符(默认为/)
返回值: 相对路径字符串,如 com/example/MyClass.kt
示例:
val file = KotlinFile("com.example", typeSpec)
// 使用默认文件名
val path1 = file.toRelativePath()
// "com/example/MyClass.kt"
// 自定义文件名
val path2 = file.toRelativePath(filename = "CustomName")
// "com/example/CustomName.kt"
// 脚本文件
val path3 = file.toRelativePath(isScript = true)
// "com/example/MyClass.kts"
// Windows 路径分隔符
val path4 = file.toRelativePath(separator = "\\")
// "com\example\MyClass.kt"将 KotlinFile 转换为 Kotlin 代码字符串。
fun KotlinFile.writeToKotlinString(): String示例:
val file = KotlinFile("com.example", typeSpec)
val kotlinCode = file.writeToKotlinString()
println(kotlinCode)val personClass = KotlinSimpleTypeSpec(KotlinTypeSpec.Kind.CLASS, "Person") {
addModifier(KotlinModifier.DATA)
primaryConstructor(KotlinConstructorSpec {
addParameter("name", ClassName("kotlin", "String").ref()) {
immutableProperty()
}
addParameter("age", ClassName("kotlin", "Int").ref()) {
immutableProperty()
}
})
}
val file = KotlinFile("com.example.model", personClass) {
addFileComment("Generated model class")
indent(" ")
}
println(file.writeToKotlinString())输出:
// Generated model class
package com.example.model
data class Person(val name: String, val age: Int)val file = KotlinFile("com.example.utils".parseToPackageName()) {
// 顶层属性
addProperty(KotlinPropertySpec("APP_NAME", ClassName("kotlin", "String").ref()) {
addModifier(KotlinModifier.CONST)
initializer("\"MyApp\"")
})
// 顶层函数
addFunction(KotlinFunctionSpec("log", ClassName("kotlin", "Unit").ref()) {
addParameter("message", ClassName("kotlin", "String").ref())
addCode("println(\"[\$APP_NAME] \$message\")")
})
// 辅助类
addSimpleClassType("Logger") {
addModifier(KotlinModifier.INTERNAL)
}
}输出:
package com.example.utils
const val APP_NAME: String = "MyApp"
internal class Logger
fun log(message: String) {
println("[$APP_NAME] $message")
}val suppressAnnotation = ClassName("kotlin", "Suppress").kotlinAnnotationRef {
addMember("\"UNUSED\", \"DEPRECATION\"")
status {
useSite = KotlinAnnotationUseSite.FILE
}
}
val jvmNameAnnotation = ClassName("kotlin.jvm", "JvmName").kotlinAnnotationRef {
addMember("\"MyClassUtils\"")
status {
useSite = KotlinAnnotationUseSite.FILE
}
}
val file = KotlinFile("com.example", typeSpec) {
addAnnotation(suppressAnnotation)
addAnnotation(jvmNameAnnotation)
}输出:
@file:Suppress("UNUSED", "DEPRECATION")
@file:JvmName("MyClassUtils")
package com.example
class MyClassval file = KotlinFile("com.example", typeSpec) {
addStaticImport("kotlin.io.println")
addStaticImport(
ClassName("kotlin.collections", "Collections"),
"emptyList",
"emptyMap",
"emptySet"
)
}输出:
package com.example
import kotlin.io.println
import kotlin.collections.Collections.emptyList
import kotlin.collections.Collections.emptyMap
import kotlin.collections.Collections.emptySet
class MyClassval scriptFile = KotlinFile {
addStatement("val numbers = listOf(1, 2, 3, 4, 5)")
addStatement("val doubled = numbers.map { it * 2 }")
addStatement("println(doubled)")
// 脚本中也可以定义函数
addFunction(KotlinFunctionSpec("helper", ClassName("kotlin", "Unit").ref()) {
addCode("println(\"Helper function\")")
})
addStatement("helper()")
}
// 保存为 .kts 文件
val scriptPath = scriptFile.toRelativePath(isScript = true)输出:
val numbers = listOf(1, 2, 3, 4, 5)
val doubled = numbers.map { it * 2 }
println(doubled)
fun helper() {
println("Helper function")
}
helper()val file = KotlinFile("com.example.api") {
// 文件注释
addFileComment("API definitions\nGenerated on: 2025-12-23")
// 文件级注解
addAnnotation(ClassName("kotlin", "Suppress").kotlinAnnotationRef {
addMember("\"unused\"")
status { useSite = KotlinAnnotationUseSite.FILE }
})
// 顶层常量
addProperty(KotlinPropertySpec("API_VERSION", ClassName("kotlin", "Int").ref()) {
addModifier(KotlinModifier.CONST)
initializer("1")
})
// 接口定义
addSimpleInterfaceType("Api") {
addFunction(KotlinFunctionSpec("call", ClassName("kotlin", "String").ref()))
}
// 实现类
addSimpleClassType("ApiImpl") {
addModifier(KotlinModifier.INTERNAL)
addSuperinterface(ClassName("com.example.api", "Api").ref())
addFunction(KotlinFunctionSpec("call", ClassName("kotlin", "String").ref()) {
addModifier(KotlinModifier.OVERRIDE)
addCode("return \"API v\$API_VERSION\"")
})
}
// 工厂函数
addFunction(KotlinFunctionSpec("createApi", ClassName("com.example.api", "Api").ref()) {
addCode("return ApiImpl()")
})
name("Api")
indent(" ")
}输出:
// API definitions
// Generated on: 2025-12-23
@file:Suppress("unused")
package com.example.api
const val API_VERSION: Int = 1
interface Api {
fun call(): String
}
internal class ApiImpl : Api {
override fun call(): String = "API v$API_VERSION"
}
fun createApi(): Api = ApiImpl()fun generateModels(packageName: PackageName): List<KotlinFile> {
val models = listOf("User", "Product", "Order")
return models.map { modelName ->
KotlinFile(packageName) {
addSimpleClassType(modelName) {
addModifier(KotlinModifier.DATA)
primaryConstructor(KotlinConstructorSpec {
addParameter("id", ClassName("kotlin", "Long").ref()) {
immutableProperty()
}
})
}
name(modelName)
}
}
}
// 使用
val files = generateModels("com.example.model".parseToPackageName())
files.forEach { file ->
val path = file.toRelativePath()
val code = file.writeToKotlinString()
// 写入文件系统
File(path).apply {
parentFile.mkdirs()
writeText(code)
}
}KotlinFile.writeTo() 方法接受 KotlinWriteStrategy 参数,用于控制代码生成行为:
// 使用默认策略(toString)
val code = file.writeToKotlinString()
// 自定义策略
val customStrategy = object : KotlinWriteStrategy {
override fun omitPackage(packageName: PackageName): Boolean {
// 自定义包省略逻辑
return packageName.toString() == "kotlin"
}
}
val code = buildString {
file.writeTo(this, customStrategy)
}- 使用
name()方法显式设置文件名 - 如果未设置,默认使用第一个类型的名称
- 对于纯函数/属性文件,建议手动指定有意义的名称
KotlinFile("com.example") {
addFunction(helperFunction)
name("Helpers") // 明确指定文件名
}- 使用
PackageName类型而非字符串 - 使用
parseToPackageName()扩展函数转换字符串
val packageName = "com.example.app".parseToPackageName()
KotlinFile(packageName, typeSpec)- 使用
staticImports简化常用成员调用 - 使用
alwaysQualify避免名称冲突 - 避免重复导入同一类型
- 必须使用
KotlinAnnotationUseSite.FILE - 多个注解会按添加顺序生成
- 注解在
package声明之前
- 属性 → 类型 → 函数(按此顺序生成)
- 相关元素分组添加
- 使用空行分隔不同逻辑块
- 使用
KotlinFile { }DSL - 可包含顶层语句、函数、属性
- 使用
toRelativePath(isScript = true)生成.kts路径
A: KotlinFile 至少需要一个元素(类型、函数或属性)。如果需要空脚本,使用:
KotlinFile {
addStatement("// Empty script")
}A: 使用 indent() 方法设置缩进,使用自定义 KotlinWriteStrategy 控制更多细节。
A: 文件级注解使用 @file: 语法,在 package 声明之前。类注解直接在类声明之前。
A: 创建 List<KotlinFile>,遍历并使用 toRelativePath() 和 writeToKotlinString() 输出。
- KotlinTypeSpec - 类型规范
- KotlinFunctionSpec - 函数规范
- KotlinPropertySpec - 属性规范
- PackageName - 包名
- CodeValue - 代码值