- 配置
// As-3.4.1及其以上 + gradle5.1.1-all + auto-service:1.0-rc4
api 'com.google.auto.service:auto-service:1.0-rc4'
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
java項目避免輸出亂碼奋姿,增加配置
// java控制臺輸出中文亂碼
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
- 繼承AbstractProcessor,重寫init和實現(xiàn)process方法
- 增加@AutoService(Processor.class)注解
- 配置注解
- SupportedAnnotationTypes 設置要處理的注解類型
- SupportedSourceVersion 設置jdk編譯版本
- SupportedOptions 設置接收的參數(shù)
- 從init方法中初始化基本工具類實例
// 初始化
/*操作Element的工具類(類梳猪,函數(shù),屬性蒸痹,都屬于Element)*/
elementUtils = processingEnvironment.getElementUtils();
/*類類型工具春弥,用于操作TypeMirror的工具類*/
typeUtils = processingEnvironment.getTypeUtils();
/*用于打印日志*/
messager = processingEnvironment.getMessager();
/*用于生成文件*/
filer = processingEnvironment.getFiler();
//獲取參數(shù),傳遞參數(shù)后文介紹
Map<String, String> options = processingEnv.getOptions();
if (options.size() == 0 || !options.containsKey("eventBusIndex")) {
messager.printMessage(Diagnostic.Kind.NOTE, "需要傳遞一個類索引類的全類名");
return;
}
eventBusIndexClassName = options.get("eventBusIndex");
-
在process方法中處理Element
- roundEnv.getElementsAnnotatedWith(Subscribe.class) 獲取Subscribe注解的所有元素
- element.getKind() 獲取該元素類型叠荠,是類匿沛,函數(shù)或者字段等
- element.getModifiers() 獲取修飾符
- executableElement.getReturnType() 獲取返回值
- executableElement.getParameters() 獲取參數(shù)
- executableElement.getEnclosingElement() 獲取該函數(shù)的所屬的類元素
executableElement表示這是一個可執(zhí)行的元素即方法
- elementUtils.getTypeElement("全類名") 根據(jù)字符串獲取類的類型用于javapoet自動生成文件的類型
- TypeName 某個屬性或者參數(shù)的類型,一般的可以使用ClassName.get獲取榛鼎,可傳遞class逃呼,TypeElement,TypeMirror等者娱,復合型的類型抡笼,例如含有泛型的可以使用ParameterizedTypeName.get獲取,例如Map<T1,T2>黄鳍,第一個參數(shù)就傳遞ClassName.get(Map.class)推姻,T1,T2依次傳遞即可框沟。
- 生成一個類藏古,應該用倒序的方式去寫,先把類的結構搭建起忍燥,然后需要什么再添加什么拧晕,例如:
JavaFile.builder(packageName, typeSpec).build().writeTo(filer);
這就是生成一個類的方法,但是這里需要傳入報名和TypeSpec灾前,所以就去創(chuàng)建一個typeSpec防症,這是一個類結構的封裝對象。TypeSpec typeSpec = TypeSpec.classBuilder(className).build()
這句話就能生成一個類結構的封裝對象,className就是類名蔫敲,然后我們可以通過TypeSpec的builder去添加很多關于類的所有東西饲嗽,最后再build:- 實現(xiàn)一個接口使用
addSuperinterface
或者繼承一個類使用superclass
當然都需要傳遞接口或者要繼承的類的類型 - 同樣可以添加類的修飾符
addModifiers
,可傳遞多個 - 可以添加字段
addField
奈嘿,添加的字段可以創(chuàng)建一個FieldType貌虾,需要字段名,類型以及修飾符裙犹,例如:
FieldSpec.builder(/*字段類型,參考上文的TypeName*/fieldType, /*字段名*/"info", /*修飾符*/ Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL) .build();
- 靜態(tài)代碼塊
addStaticBlock
尽狠,可以創(chuàng)建一個CodeBlock.builder(),然后內部的每一行代碼都可以通過add添加叶圃,但是需要注意袄膏,使用add添加的代碼不會自動添加分號 - 添加方法
addMethod
,可以創(chuàng)建一個 MethodSpec.methodBuilder("方法名")來添加掺冠,可以添加方法修飾符(addModifiers)沉馆,方法參數(shù)(addParameter),方法返回值(returns)德崭,方法體(addStatement或者addCode斥黑,前者每句結尾會自動添加分號,后者不會)眉厨。 - 然后在添加的過程中還有一個重要的知識點就是format的占位符
$N
用來表示變量名$S
用來表示字符串$T
用來表示類$L
用來表示枚舉的值然后每一個占位符都需要一個值來填充锌奴,例如要生成
info = new HashMap<Class<?>, String>();
這樣一句話就可以:addStatement(/*format*/"$N = new $T<$T, $T>()" /*對應值*/ "info",ClassName.get(HashMap.class), ClassName.get(Class.class),ClassName.get(String.class) )
這樣生成出來就是上邊那句話了,
$N
和$S
的傳值都是字符串憾股,顯示出來前者會去掉引號變成一個變量鹿蜀,后者就是字符串顯示。