這系列的文章不會講完全部 KSP 的實作,畢竟我也還正在實作中,不過實作的方向應該是跟前幾篇講的差不多,只是換一個 annotation processor 的工具而已。
class KspProcessor(
private val codeGenerator: CodeGenerator,
private val logger: KSPLogger,
private val options: Map<String, String>
): SymbolProcessor {
override fun process(resolver: Resolver): List<KSAnnotated> {
// 略
}
}
在 KSP 裡面,他有提供一些工具可以做使用,像是 CodeGenerator
,是一個官方給的讓你可以直接產生 Java 或 Kotlin 的程式碼,類似像 KotlinPoet 的東西,但我覺得是比較陽春一點,KotlinPoet 的 API 寫出來的程式也比較易讀,也有比較多功能的 API 可以用,至於效能的部分,可能要在做一下實驗會比較了解。
以下是官方範例中 CodeGenerator
的用法:
val javaFile = codeGenerator.createNewFile(Dependencies(false), "", "Generated", "java")
javaFile.appendText("class Generated {}")
val fileKt = codeGenerator.createNewFile(Dependencies(false), "", "HELLO", "java")
fileKt.appendText("public class HELLO{\n")
fileKt.appendText("public int foo() { return 1234; }\n")
fileKt.appendText("}")
用法真的比 KotlinPoet 單純很多,只要直接 append 程式碼就好,但在寫的時候可能就需要注意一下輸出的時候,程式碼的縮排是否會像我們想像的那樣。
除了 CodeGenerator
,還有 KSPLogger
。一樣也是封裝的好好的,不用我們額外做事情就可以順順地用,很棒!
interface KSPLogger {
fun logging(message: String, symbol: KSNode? = null)
fun info(message: String, symbol: KSNode? = null)
fun warn(message: String, symbol: KSNode? = null)
fun error(message: String, symbol: KSNode? = null)
fun exception(e: Throwable)
}
另外,KSP 的 option 也可以在它提供 options
的 map 裡面拿到,我覺得這個真的是相當方便。./
// 加在要用 annotation processor 的 module 的 kts 檔裡面
ksp {
arg("pureKotlinParser", "true")
}
最後一個未解的謎團就是 process
function 裡的 Resolver
,大部分的 API 其實跟 Java 版本的 annotation processor 差不多,官方甚至有列出一張表,來對照 KSP 的 API ,有興趣的朋友可以去了解一下。
目前 KtRssReader KSP 的版本還在施工中,有興趣關注的朋友可以關注一下這個 branch ,feature 開發完,code review 過了沒什麼問題才會 release 。大致上的改動,會把 annotation processor 從 KAPT 改成 KSP ,跑跑看測試有沒有需要修改的部分,其他程式碼的實作內容不會變動太多,我會努力抽空實作的... ? 那如果想要看到更完整的 KSP 範例,可以直接下載官方的範例 project ,直接給它玩玩看會更有上手的感覺,更多資訊也可以參考 KSP github 。