ksp注解处理器基本使用
引入依赖
新建一个项目,在项目build.gradle中引入依赖:
dependencies {
classpath 'com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:1.6.21-1.0.6'
}
编写注解
新建一个模块,编写想要处理多注解
这个模块的build.gradle只需要简单配置为一个java-library就行,例如:
plugins {
id 'java-library'
id 'kotlin'
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
接下来新建文件编写注解,注解编写方法可参考官方文档
例如这样:
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.SOURCE)
annotation class Hello()
注解处理
新建一个模块,用作注解处理
- build.gradle基础配置
plugins {
id 'java-library'
id 'kotlin'
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
- 依赖配置
首先需要引入依赖库,其中'com.google.devtools.ksp:symbol-processing-api:1.6.21-1.0.6'
是必须的,"com.squareup:kotlinpoet:1.12.0"
与'com.squareup:kotlinpoet-ksp:1.12.0'
可选,这两个库可以使处理符号生成文件更方便
implementation 'com.google.devtools.ksp:symbol-processing-api:1.6.21-1.0.6'
implementation "com.squareup:kotlinpoet:1.12.0"
implementation 'com.squareup:kotlinpoet-ksp:1.12.0'
接下来引入编写的注解模块
例如:
implementation(project(":hello"))
- 实现
SymbolProcessor
新建一个类继承自com.google.devtools.ksp.processing.SymbolProcessor
,实现
process方法,在方法中获取所有被注解的符号依次处理,符号处理使用ksp,具体参考ksp官方文档
例如:
class HelloProcessor(private val environment: SymbolProcessorEnvironment): SymbolProcessor {
override fun process(resolver: Resolver): List<KSAnnotated> {
resolver.getSymbolsWithAnnotation(Hello::class.java.name).forEach {
if (it is KSFunctionDeclaration && it.containingFile != null) {
FileSpec.builder(packageName = it.packageName.asString(), "Hello")
.addType(TypeSpec.classBuilder("Hello").build())
.addFunction(FunSpec.builder("hello")
.addModifiers(KModifier.PRIVATE)
.addStatement("println(\"hello\")")
.build()
)
.build()
.writeTo(environment.codeGenerator, Dependencies(false, it.containingFile!!))
}
}
return emptyList()
}
}
- 实现
SymbolProcessorProvider
新建一个类继承自com.google.devtools.ksp.processing.SymbolProcessorProvider
,实现create方法,返回刚才实现的SymbolProcessor
类的实例
例如:
class HelloProvider: SymbolProcessorProvider {
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
return HelloProcessor(environment)
}
}
- 入口配置
在注解处理器模块main下新建一个resources资源包,继续在resources下新建META-INF包,继续,在META-INF下新建一个gradle包,在gradle下新建一个文件,文件名称为incremental.annotation.processors
,此文件内容为刚才实现的SymbolProcessor
类的全名;接下来在META-INF下再新建一个services包,包下新建文件,文件名为com.google.devtools.ksp.processing.SymbolProcessorProvider
,文件内容为刚才实现的SymbolProcessorProvider
类的全名。
最终目录结构如下:
新建一个模块使用它
新建一个模块
- 引入注解模块:
implementation(project(":hello"))
- 引入注解处理器ksp插件
id 'com.google.devtools.ksp'
- 引入自己实现的注解处理模块
ksp(project(":hello-compiler"))
- 在此模块中新建一个文件使用这个注解
例如:
@Hello
fun test() {
println("test")
}
- 编译,会发现在build目录中已生成新的文件,如下:
至此,成功!!
补充一些内容:
我们使用注解生成的文件后续肯定是要引用的,为了能在项目其他文件中引用,我们需要在gradle文件(当然也可能是kts文件,以下一gradle文件为例)中配置sourceSet来包含生成文件所在的目录,例如只希望debug引用我们可以这样配置:
kotlin {
sourceSets.debug {
kotlin.srcDir("build/generated/ksp/debug/kotlin")
}
}
如果还希望release也可以访问,我们可以再添加这样的配置:
sourceSets.release {
kotlin.srcDir("build/generated/ksp/release/kotlin")
}