编译时注解学习三之 注解处理器AbstractProcessor工具和Element属性简述

1 如何读取build.gradle配置的常量

配置,读取:

@SupportedOptions({"CLASSNAME"})
@SupportedAnnotationTypes("com.ldx.annotationlib.BindView")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
//@AutoService(Processor.class)
public class AptProcessor extends AbstractProcessor {

    private Map<String,String> mOptionMap;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        mOptionMap = processingEnv.getOptions();
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        if (set != null && set.size() > 0){

            Set<? extends Element>  elements = roundEnvironment.getElementsAnnotatedWith(BindView.class);
            for (Element element : elements) {
                VariableElement variableElement = (VariableElement) element;
         		//读取配置参数
                mMessager.printMessage(Diagnostic.Kind.NOTE,"aptprocessor     "+mOptionMap.get("CLASSNAME"));

                createFile(enclosingElement, bindViewFiledClassType, bindViewFiledName, bindAnnotation.value());
            }

            return true;
        }
        return false;
    }

build.gradle中配置(如何配置编译时注解变量):

 javaCompileOptions {
            annotationProcessorOptions {
                arguments = ["xxxx":"xxxxx", "CLASSNAME":"lidxclassname"]

            }
        }

2 打印信息

由于在编译期,所以无法利用System,log,打印信息,系统提供了Messager工具进行信息的打印。
private Messager mMessager = processingEnv.getMessager();;
在这里插入图片描述
第一个参数Kind标识日志的级别,包括:

 public static enum Kind {
        ERROR,
        WARNING,
        MANDATORY_WARNING,
        NOTE,
        OTHER;

        private Kind() {
        }
    }

第二个参数为打印信息,后面参数Element为需要打印的Element。

3 Elements 工具

Elements mElementsUtils = processingEnv.getElementUtils();
编译时注解学习三之 注解处理器AbstractProcessor工具和Element属性简述_第1张图片
编译时注解学习三之 注解处理器AbstractProcessor工具和Element属性简述_第2张图片

  //包名
                mMessager.printMessage(Diagnostic.Kind.NOTE,"aptprocessor     "+mElementsUtils.getPackageOf(enclosingElement).asType().toString());
                mMessager.printMessage(Diagnostic.Kind.NOTE,"aptprocessortwo     "+mElementsUtils.getBinaryName(enclosingElement));
                mMessager.printMessage(Diagnostic.Kind.NOTE,"aptprocessortwo     "+mElementsUtils.getPackageOf(enclosingElement).getQualifiedName().toString());
                mMessager.printMessage(Diagnostic.Kind.NOTE,"aptprocessortwo     "+mElementsUtils.isDeprecated(enclosingElement));
                mMessager.printMessage(Diagnostic.Kind.NOTE,"aptprocessortwo     "+mElementsUtils.getPackageElement("com.ldx.canvasdrawdemo").getQualifiedName());

4 Filer

Filer mFilerUtils = processingEnv.getFiler();
完全类名:javax.annotation.processing.Filer,注解处理器可用此创建新文件(源文件、类文件、辅助资源文件)。由此方法创建的源文件和类文件将由管理它们的工具(javac)处理
编译时注解学习三之 注解处理器AbstractProcessor工具和Element属性简述_第3张图片
编译时注解学习三之 注解处理器AbstractProcessor工具和Element属性简述_第4张图片
apt常用方法为:
编译时注解学习三之 注解处理器AbstractProcessor工具和Element属性简述_第5张图片
第一个参数为生成的java文件的全限定名(也就是包名和文件名,写法应该是包名(com.ldx.xx)然后加上一个点(.)在加上文件名),例如要生成com.ldx.xx.demo.java,第一个参数写法为"com.ldx.xx.demo",其中demo就是文件名。
第二个参数是与此文件的创建有因果关联的类型或包元素,该参数可以省略或者为 null,类型为一个数组,一般写法为new Element[]{}或者为null。

  private void createFile(TypeElement enclosingElement, String bindViewFiledClassType, String bindViewFiledName, int id) {
        String pkName = mElementsUtils.getPackageOf(enclosingElement).getQualifiedName().toString();
        String packName = mElementsUtils.getPackageOf(enclosingElement).asType().toString();
        String className = enclosingElement.getSimpleName().toString();
        try {
            JavaFileObject jfo = mFilerUtils.createSourceFile(pkName + "."+className+ "$ViewBinding", new Element[]{});
            Writer writer = jfo.openWriter();
            writer.write(brewCode(className,pkName, bindViewFiledClassType, bindViewFiledName, id));
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private String brewCode(String className,String pkName, String bindViewFiledClassType, String bindViewFiledName, int id) {
        StringBuilder builder = new StringBuilder();
        builder.append("package " + pkName + ";\n\n");
        builder.append("public class " + className + "$ViewBinding { \n\n");
        builder.append("public static void main(String[] args){ \n\n");
        String info = String.format("%s %s = findViewById(%d)", bindViewFiledClassType, bindViewFiledName, id);
        builder.append("System.out.println(\"" + info + "\");\n\n");
        builder.append("}\n\n");
        builder.append("}");
        return builder.toString();
    }

5 ElementKind

如何判断Element的类型呢,需要用到ElementKind,ElementKind为元素的类型,元素的类型判断不需要用instanceof去判断,而应该通过getKind()去判断对应的类型
类型 说明
PACKAGE 包
ENUM 枚举
CLASS 类
ANNOTATION_TYPE 注解
INTERFACE 接口
ENUM_CONSTANT 枚举常量
FIELD 字段
PARAMETER 方法参数
LOCAL_VARIABLE 局部变量
METHOD 方法
CONSTRUCTOR 构造方法
TYPE_PARAMETER 类型参数

  Set<? extends Element>  elements = roundEnvironment.getElementsAnnotatedWith(BindView.class);
            for (Element element : elements) {
                ElementKind kind = element.getKind();
                if (kind.isField()){
                   mMessager.printMessage(Diagnostic.Kind.NOTE,"aptprocessor     "+"element 是 Field,利用VariableElement进行强转");
                }
                }

6 TypeMirror

TypeMirror是一个接口,表示Java编程语言中的类型。这些类型包括基本类型、引用类型、数组类型、类型变量和null类型等等

类型 说明
ArrayType 表示数组类型
DeclaredType 表示声明类型(类或接口类型)
ErrorType 表示异常类或接口类型
ExecutableType 表示executable类型(方法、构造方法、初始化)
NoType 表示在实际类型不适合的地方使用的伪类型
NullType 表示null类型
PrimitiveType 表示基本数据类型
ReferenceType 表示引用类型
TypeVariable 表示类型变量
WildcardType 表示通配符类型参数

 for (Element element : elements) {
                ElementKind kind = element.getKind();
                if (kind.isField()){
                    mMessager.printMessage(Diagnostic.Kind.NOTE,"aptprocessor     "+"element 是 Field,利用VariableElement进行强转");
                    TypeMirror mirror = element.asType();
                    
                    TypeKind kind1 = mirror.getKind();
                    
                }

如果Element是一个VariableElement,variableElement.asType().toString()可以获取它的全类名。

  String bindViewFiledClassType = variableElement.asType().toString();
                //变量名
                mMessager.printMessage(Diagnostic.Kind.NOTE,"aptprocessor     "+bindViewFiledClassType);

输出:
android.widget.TextView

7 TypeKind

TypeKind为类型的属性,类型的属性判断不需要用instanceof去判断,而应该通过getKind()去判断对应的属性

类型 说明
BOOLEAN 基本类型boolean
INT 基本类型int
LONG 基本类型long
FLOAT 基本类型float
DOUBLE 基本类型double
VOID 对应于关键字void的伪类型
NULL null类型
ARRAY 数组类型
PACKAGE 对应于包元素的伪类型
EXECUTABLE 方法、构造方法、初始化
DECLARE 声明类型

 for (Element element : elements) {
                ElementKind kind = element.getKind();
                if (kind.isField()){
                    mMessager.printMessage(Diagnostic.Kind.NOTE,"aptprocessor     "+"element 是 Field,利用VariableElement进行强转");
                    TypeMirror mirror = element.asType();
                    
                    TypeKind kind1 = mirror.getKind();
                    
                }

8 Types

Types mTypesUtils = processingEnv.getTypeUtils();
Type操作工具,包括对TypeMirror,TypeKind,DeclaredType
编译时注解学习三之 注解处理器AbstractProcessor工具和Element属性简述_第6张图片编译时注解学习三之 注解处理器AbstractProcessor工具和Element属性简述_第7张图片
asElement,根据特定TypeMirror获取与之关联的ElementType。
contains,是否一个TypeMirror包含另外一个TypeMirror,类似数组和普通元素。
。。。。。。。

编译时注解学习一之 Element元素
编译时注解学习二之 注解处理器初探AbstractProcessor
编译时注解学习三之 注解处理器AbstractProcessor工具和Element属性简述
编译期注解学习四 简单的view注入框架
编译期注解学习五 - ElementKind,TypeKind,不同Element类型判断
编译期注解学习六- 生成java文件javapoet
编译期注解学习七-如何进行调试
编译时注解学习八 -模板文件读取

你可能感兴趣的:(编译期注解学习)