Java注解處理器使用注意事項(xiàng)
目錄
[TOC]
注解
元注解
@Target
用于標(biāo)記可以應(yīng)用于哪些類(lèi)型上.
類(lèi)型說(shuō)明
元素類(lèi)型 | 適用場(chǎng)合 |
---|---|
ANOTATION_TYPE | 注解類(lèi)型聲明 |
PACKAGE | 包 |
TYPE | 類(lèi),枚舉,接口,注解 |
METHOD | 方法 |
CONSTRUCTOR | 構(gòu)造方法 |
FIELD | 成員域,枚舉常量 |
PARAMETER | 方法或構(gòu)造器參數(shù) |
LOCAL_VARIABLE | 局部變量 |
TYPE_PARAMETER | 類(lèi)型參數(shù) |
TYPE_USE | 類(lèi)型用法 |
@Retention
用于標(biāo)注注解保留時(shí)間
類(lèi)型說(shuō)明
保留類(lèi)型 | 說(shuō)明 |
---|---|
SOURCE | 只保留到源碼中,編譯出來(lái)的class不存在 |
CLASS | 保留到class文件中,但是JVM不會(huì)加載 |
RUNTIME | 一直存在,JVM會(huì)加載,可用反射獲取 |
注解處理器
方法重載注意事項(xiàng)
- 為兼容
JDK_6
,最好重載方法getSupportedAnnotationTypes
和getSupportedSourceVersion
而不是使用注釋@SupportedAnnotationTypes
和@SupportedSourceVersion
注解處理器的注冊(cè)
方式一
res/META-INF/services/javax.annotation.processing.Processor
添加注解處理器的類(lèi)全路徑及名稱(chēng),如果有多個(gè)注解處理器,換行分割.
舉例:
com.yxf.socketframe.annotation.ClientCallbackProcessor
com.yxf.socketframe.annotation.ServerInterfaceProcessor
有一個(gè)非常巨大的坑,如果是在Android Studio中做這些事情,需要在庫(kù)的build.gradle中添加如下配置
sourceSets {
main {
java {
srcDir 'src'
}
resources {
srcDir 'res'
}
}
}
不然注解處理器不生效.
方式二
添加對(duì)谷歌自動(dòng)注冊(cè)注解庫(kù)的引用
implementation ‘com.google.auto.service:auto-service:1.0-rc4’
在注解處理器類(lèi)前面聲明
@AutoService(Processor.class)
配置
在項(xiàng)目app的build.gradle中添加
android {
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
includeCompileClasspath true
}
}
}
}
或者使用annotationProcessor
來(lái)編譯有注解處理器的部分.
常用實(shí)現(xiàn)
getSupportedSourceVersion
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
getSupportedAnnotationTypes
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> annotations = new LinkedHashSet<String>();
annotations.add(ServerInterface.class.getCanonicalName());
return annotations;
}
process
從EventBus源碼中借鑒
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
round++;
messager.printMessage(Diagnostic.Kind.NOTE, "Processing round " + round + ", new annotations: " +
!set.isEmpty() + ", processingOver: " + roundEnvironment.processingOver());
if (roundEnvironment.processingOver()) {
if (!set.isEmpty()) {
messager.printMessage(Diagnostic.Kind.ERROR,
"Unexpected processing state: annotations still available after processing over");
return false;
}
}
if (set.isEmpty()) {
return false;
}
if (writerRoundDone) {
messager.printMessage(Diagnostic.Kind.ERROR,
"Unexpected processing state: annotations still available after writing.");
}
if (!generateSourceFile(set, roundEnvironment)) {
return false;
}
writerRoundDone = true;
return true;
}
Element
類(lèi)型說(shuō)明
Element | 說(shuō)明 |
---|---|
TypeElement | 一般是類(lèi)或者接口元素 |
ExecutableElement | 類(lèi)方法或者接口方法元素 |
VariableElement | 成員變量,參數(shù)元素 |
屬性獲取
屬性的獲取感覺(jué)有點(diǎn)讓人心累,無(wú)法直接獲得所屬對(duì)象的class.
一般通過(guò)Element.getQualifiedName()
,Element.getSimpleName()
這兩個(gè)方法獲得類(lèi)名和路徑.
通過(guò)Element.getKind()
獲得元素類(lèi)型.
通過(guò)ExecutableElement.getReturnType().getKind()
獲得方法返回類(lèi)型.
通過(guò)VariableElement.asType().toString()
獲得參數(shù)類(lèi)型,或者通過(guò)VariableElement.asType().getKind()
獲取,但是這種方式只能獲得基礎(chǔ)類(lèi)型的類(lèi)型.
通過(guò)Element.getEnclosedElements()
獲得子元素,通過(guò)Element.getEnclosingElement()
獲得父元素.
注意
應(yīng)當(dāng)注意的是,在生成Java源文件的代碼中,生產(chǎn)的內(nèi)部變量盡可能添加下劃線(xiàn),以避免和動(dòng)態(tài)參數(shù)產(chǎn)生變量名沖突
注解處理器和庫(kù)之間應(yīng)當(dāng)分離作為兩個(gè)庫(kù)
如果自建Java庫(kù),注解處理器和注解分離,則在這個(gè)庫(kù)中使用的注解,注解處理器將不會(huì)執(zhí)行,所以不要在自己的庫(kù)中使用自己的注解.
process
方法返回false會(huì)停止編譯,如果編譯出現(xiàn)問(wèn)題,可以通過(guò)Messager
打印錯(cuò)誤信息,并且process
返回false.