Auto Service 可以幫我們註冊 Annotation processor 到 java 的 service loader 裡面,我們的 processor 就可以在 build 的時候被呼叫。首先要在 processor module 裡面 (processor/src/main/resources/META-INF/services/
) 加入一個名為 javax.annotation.processing.Processor
的 configuration 檔案。這個檔案要寫你的 processor 的完整路徑,包含 package name ,完整檔案可以參考這邊。
tw.ktrssreader.processor.RssAnnotationProcessor
設定好 auto service 之後,我們就可以來撰寫 processor 了!我們只要透過 @AutoService
來標注我們的 processor ,在 compile 的時候就會呼叫內部的 process
方法。除了要覆寫 process
方法外,我們還要覆寫 getSupportedAnnotationTypes
來指定要處理哪些 annotation ,在這邊我們要指定之前訂好的四個 annotation : RssTag
、 RssRawData
、 RssAttribute
和 RssValue
。
@AutoService(Processor::class)
class RssAnnotationProcessor : AbstractProcessor() {
override fun getSupportedAnnotationTypes(): MutableSet<String> {
return mutableSetOf(
RssTag::class.java.canonicalName,
RssRawData::class.java.canonicalName,
RssAttribute::class.java.canonicalName,
RssValue::class.java.canonicalName
)
}
override fun process(typeElementSet: MutableSet<out TypeElement>?, roundEnvironment: RoundEnvironment?): Boolean {
...
}
}
接下來我們來看 process 方法裡的 RoundEnvironment
,他指的是被 annotation 標注的程式碼資訊。我們可以從中獲得被標注的元素。在產生程式碼之前,我們需要做的就是先獲得標注的結構和資訊,所以我們可以先實作一個方法來拿到標註有 @RssTag
且它的名稱是 channel
的類別,先判別第一層結構。
private inline fun generateParsers(roundEnv: RoundEnvironment?, crossinline action: (Boolean, Element) -> Unit) {
roundEnv?.getElementsAnnotatedWith(RssTag::class.java)?.forEach{
if (it?.kind == ElementKind.CLASS) {
val rssTag = it.getAnnotation(RssTag::class.java)
val isRoot = rssTag?.name == CHANNEL
action(isRoot,it)
}
}
}
可以用 getElementsAnnotatedWith
拿到有 @RssTag
的元素,然後判斷它是不是 class 層級和它的 tag 名稱,接著就可以執行 action ,這邊把 action 定義成一個 lambda ,讓使用這個 function 的人可以自己決定要做什麼動作。