首先我們要在有用到 annotation processor 的 module 的 build.gradle 裡面加上 kapt 的 plugin 宣告。這些 module 包含:
:processor
:processorTest
apply plugin: 'kotlin-kapt'
接著要在 :processor
module 裡面加入兩個 library :Kotlin Poet 和 auto service 。
dependencies {
implementation 'com.squareup:kotlinpoet:1.6.0'
implementation "com.google.auto.service:auto-service:1.0-rc6"
}
Kotlin Poet 是 Square 出的一個專門產生 kt 檔的 library ,我們可以用它擴充性高且泛用的 API 來產生 parser 的程式碼,其大多數的 API 都是以 Builder 模式寫成的,非常的簡單易用。舉個簡單的例子,假設我們的目標是產生下面的 extension function:
fun Element.getAttributeOrNull(tag: String): String? {
val attr = getAttribute(tag) ?: return null
return if (attr.isEmpty() || attr.isBlank()) null else attr
}
它使用到了 DOM parser 裡面的 Element
,以 Element
為底去寫一個 extension 。這樣子在 Kotlin Poet 可以這樣寫:
const val METHOD_GET_ATTR_OR_NULL = "getAttributeOrNull"
val elementClass = ClassName("org.w3c.dom", "Element")
private fun getAttributeOrNullFunSpec() = FunSpec.builder(METHOD_GET_ATTR_OR_NULL)
.receiver(elementClass)
.addParameter("tag", String::class)
.addCode(
"""
|val attr = getAttribute(tag) ?: return null
|return if (attr.isEmpty() || attr.isBlank()) null else attr
""".trimMargin()
)
.returns(String::class.asTypeName().copy(nullable = true))
.build()
elementClass
裡面是指定在 org.w3c.dom.Element
的類別 ,這個類別不用特別宣告 import ,Kotlin Poet 在產生程式碼的時候會自動幫我們 import org.w3c.dom.Element
。接著,我們用 FunSpec 來組合我們的 extension function , receiver
是要以什麼為底去當 extension ,這邊用的是 Element
,也可以透過 addParameter
API 去加入參數,只要記得指定名字和型別就可以了!比較重要的地方是 addCode
這邊,可以把整段程式碼寫進去 function 裡面。最後,指定 return
的型別和 呼叫 build()
就完成這個 extension 的 generator 。這只是一個簡單的應用,後面我們會看到更複雜的用法來幫助我們完成自動化產生程式碼。