0
点赞
收藏
分享

微信扫一扫

java-apt的实现之Element详解

基本介绍

以下是官方文档对element的定义

即element是代表程序的一个元素,这个元素可以是:包、类/接口、属性变量、方法/方法形参、泛型参数。element是java-apt(编译时注解处理器)技术的基础,因此如果要编写此类框架,熟悉element是必须的。

element及其子接口

  • 各种element所代表的元素类型

简单的例子
  1. 创建注解
//注解的声明周期声明为source,意即只在编译源文件的过程中有效
@Retention(RetentionPolicy.SOURCE)
//通常一个注解只注释类,方法,或者变量,这样可以使结构更清晰。这里为了演示不同的element,把这个注解的使用对象定义为类,变量,参数,方法
@Target({ElementType.TYPE, ElementType.FIELD,ElementType.PARAMETER,ElementType.METHOD})
public @interface AAAAA {
    String value();
}

  1. 在目标类中使用注解(主module)
package com.lu.aptdemo;

import com.lu.annotation.AAAAA;

/**
 * @Author: luqihua
 * @Time: 2018/6/20
 * @Description: Test
 */
@AAAAA("this is a class")
public class Test<T> {

    @AAAAA("this is a field")
    String hello;

    @AAAAA("this is a method")
    public String say(@AAAAA("this is a parameter") String arg1) {
        return "hello world";
    }
}
  1. 创建处理器Processor(单独的一个java-module),需要用到下面三个库
 implementation 'com.google.auto:auto-common:0.10'
implementation 'com.google.auto.service:auto-service:1.0-rc4'
implementation 'com.squareup:javapoet:1.11.1'
@AutoService(Processor.class)
public class TestProcessor extends AbstractProcessor {

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> set = new HashSet<>();
        set.add(AAAAA.class.getCanonicalName());
        return set;
    }

     @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        //扫描整个工程   找出含有AAAAA注解的元素(包括类,)
        Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(AAAAA.class);
        //由于编译器的输出无法打印到控制台,因此这里借助javapoet库把需要输出的信息写入到一个新的类
        //这个是我封装的一个简单的工具
        ProcessorTool.Builder builder = new ProcessorTool.Builder().setProcessingEnv(processingEnv);
        for (Element element : elements) {
            AAAAA aaaaa = element.getAnnotation(AAAAA.class);
            if (element instanceof TypeElement) {
                builder.addArgs(" TypeElement: " + aaaaa.value());

                /*===============打印包信息=================*/
                builder.addArgs("=============================打印包信息================================");
                PackageElement packageElement = processingEnv.getElementUtils().getPackageOf(element);
                builder.addArgs("packageElement:  " + packageElement.getSimpleName().toString());
                builder.addArgs("packageElement:  " + packageElement.getQualifiedName());


                builder.addArgs("=============================打印泛型信息================================");
                List<? extends TypeParameterElement> typeParameters = ((TypeElement) element).getTypeParameters();
                for (TypeParameterElement typeParameter : typeParameters) {
                    builder.addArgs(typeParameter.getSimpleName().toString());
                }
                builder.addArgs("=============================================================");

            } else if (element instanceof ExecutableElement) {
                builder.addArgs("ExecutableElement: " + aaaaa.value());
            } else if (element instanceof VariableElement) {
                builder.addArgs(" VariableElement: " + aaaaa.value());
            }
        }
        builder.build().printLog();
        return true;
    }
}



//==========================
在主工程module的build->generate->source->apt->test->Logger.java

查看输出

package test;

import java.lang.String;

class Logger {
  void test() {
    String arg0=" TypeElement: this is a class";
    String arg1="=============================打印包信息================================";
    String arg2="packageElement.getSimpleName(): aptdemo";
    String arg3="packageElement.getQualifiedName(): com.lu.aptdemo";
    String arg4="=============================打印泛型信息================================";
    String arg5="T";
    String arg6="=============================================================";
    String arg7=" VariableElement: this is a field";
    String arg8="ExecutableElement: this is a method";
    String arg9=" VariableElement: this is a parameter";
  }
}




public class ProcessorTool {
    private ProcessingEnvironment processingEnv;
    private List<String> args = new ArrayList<>();

    public ProcessorTool(ProcessingEnvironment env) {
        this.processingEnv = env;
    }

    public ProcessorTool addArgs(String arg) {
        args.add(arg);
        return this;
    }

    /**
     * 用于打印log到文件
     */
    public void printLog() {
        TypeSpec.Builder builder = TypeSpec.classBuilder("Logger");

        MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("test");

        int len = args.size();
        for (int i = 0; i < len; i++) {
            String arg = args.get(i);
            methodBuilder.addStatement("$T arg" + i + "=$S", String.class, arg);
        }

        builder.addMethod(methodBuilder.build());

        JavaFile javaFile = JavaFile.builder("test", builder.build())
                .build();
        try {
            javaFile.writeTo(processingEnv.getFiler());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

element 接口方法

  • <R,P> R accept(ElementVisitor<R,P> v, P

示例代码

element.accept(new SimpleElementVisitor7<Void, Void>() {
                @Override
                public Void visitType(TypeElement typeElement, Void aVoid) {
                    return super.visitType(typeElement, aVoid);
                    //这是一个TypeElement
                }

                @Override
                public Void visitExecutable(ExecutableElement executableElement, Void aVoid) {
                    return super.visitExecutable(executableElement, aVoid);
                    //这是一个executableElement
                }

                @Override
                public Void visitPackage(PackageElement packageElement, Void aVoid) {
                    return super.visitPackage(packageElement, aVoid);
                    //这是一个PackageElement
                }

            }, null);
  • TypeMirror asType()

示例代码

 for (Element element : elements) {
            if (element instanceof TypeElement) {

                TypeName typeName = ClassName.get(element.asType());

                TypeSpec typeSpec = TypeSpec.classBuilder("GenerateTest")
                        .addField(typeName, "test")
                       //添加泛型信息
                       .addTypeVariable(TypeVariableName.get(((TypeElement) element).getTypeParameters().get(0)))
                        .build();

                try {
                    JavaFile.builder("com.test", typeSpec)
                            .build()
                            .writeTo(processingEnv.getFiler());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

//===================生成代码


package com.test;
//通过ClassName包装之后,在生成对应代码中会自动导入类型的包
import com.lu.aptdemo.Test;

class GenerateTest<T> {
  Test<T> test;
}

  • <A extends Annotation> A getAnnotation(Class<A> annotationType)
  • List<? extends AnnotationMirror> getAnnotationMirrors()
  • List<? extends Element> getEnclosedElements()

示例代码

 Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(AAAAA.class);
        //这个是我封装的一个简单的工具
        ProcessorTool tool = new ProcessorTool(processingEnv);
        for (Element element : elements) {
            if (element instanceof TypeElement) {
                 for (Element element1 : element.getEnclosedElements()) {
                    tool.addArgs(element1.getSimpleName().toString());
                }
            } 
        }
        tool.printLog();
        
//输出 Test类包含构造方法,属性Hello  方法say()

class Logger {
  void test() {
    String arg0="<init>";
    String arg1="hello";
    String arg2="say";
  }
}
        
  • Element getEnclosingElement()

示例代码

Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(AAAAA.class);
        //这个是我封装的一个简单的工具
        ProcessorTool tool = new ProcessorTool(processingEnv);
        for (Element element : elements) {
            tool.addArgs(element.getSimpleName().toString()+".getEnclosingElement(): "+element.getEnclosingElement().getSimpleName().toString());
        }
        tool.printLog();

//输出代码

class Logger {
  void test() {
    String arg0="Test.getEnclosingElement(): aptdemo";
    String arg1="hello.getEnclosingElement(): Test";
    String arg2="say.getEnclosingElement(): Test";
    String arg3="arg1.getEnclosingElement(): say";
  }
}

  • ElementKind getKind()
  • Set<Modifier> getModifiers()
  • Name getSimpleName()
  • Name getQualifiedName()
ExecutableElement
  • List<? extends VariableElement> getParameters()
  • TypeMirror getReturnType()
VariableElement
  • Object getConstantValue()
举报

相关推荐

0 条评论