Android 自界说编译时注解(APT)

开发者 2024-10-5 07:11:20 54 0 来自 中国
APT即为Annotation Processing Tool,它是javac的一个工具,中文意思为编译时注解处置惩罚器,APT可以用来在编译时扫描和处置惩罚注解,通过APT可以获取到注解和被注解对象的干系信息,在拿到这些信息后我们可以根据需求来自动的生成一些代码,省去了手动编写,留意,获取注解及生成代码都是在代码编译时间完成的,相比反射在运行时处置惩罚注解大大进步了步调性能。
1.png
apt是在生成.class文件之前实行,故在apt内里无法通过反射获取其他类的方法,由于反射是通过ClassLoader将Class文件加载到JVM中,在内存中举行管理。
注解处置惩罚器是运行它自己的捏造机JVM中,javac启动一个完备Java捏造机来运行注解处置惩罚器,
自界说编译注解

工程布局:

  • annotation (注解和处置惩罚器生成代码干系,有的喜欢将注解和处置惩罚器分成两个包)
  • app
annotation 模块


  • 新建java lib 定名annotation
  • build.gradle 导入依靠
dependencies {    implementation 'com.squareup:javapoet:1.13.0'    implementation 'com.google.auto.service:auto-service:1.0-rc6'    annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6'}

  • 新建java类界说注解
@Target(ElementType.TYPE)@Retention(RetentionPolicy.CLASS)public @interface NativeAnnotation {    String path() default "";}

  • 新建Processor
@AutoService(Processor.class)public class NativeProcessor extends AbstractProcessor {    @Override    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {        return false;    }}app模块


  • build.gradle 导入依靠
    implementation project(':annotation')    annotationProcessor project(':annotation')

  • 使用注解
@NativeAnnotation(path = "111")public class MainActivity extends AppCompatActivity {}在处置惩罚器内里参加log 确认处置惩罚器有没有收效
@AutoService(Processor.class)public class NativeProcessor extends AbstractProcessor {    @Override    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {        processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING," test NativeProcessor");        return false;    }}注解表明器输出的日志在build log内里检察


从log中可以看出 表明器已收效, 在process方法中可以写自己想要的逻辑,比如生成java文件
@Override    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {        processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING," test NativeProcessor");        ClassName className = ClassName.bestGuess("com.example.Useful");        TypeSpec.Builder userTypeSpec = TypeSpec.classBuilder(className)                .addModifiers(Modifier.PUBLIC);        // private int id = 0;        FieldSpec idFieldSpec = FieldSpec.builder(int.class, "id", Modifier.PRIVATE)                .initializer("0").build();        userTypeSpec.addField(idFieldSpec);        userTypeSpec.addJavadoc("解释");        JavaFile javaFile = JavaFile.builder("com.example",userTypeSpec.build()).build();        try {            javaFile.writeTo(processingEnv.getFiler());        } catch (IOException e) {            e.printStackTrace();        }        return true;    }在build目次下已生成对应文件

3.png 注解处置惩罚器核心类与函数剖析

AbstractProcessor

AbstractProcessor抽象类是实现了Processor接口,具体类变量和函数剖析如下:

  • init(ProcessingEnvironment env):init()方法会被注解处置惩罚工具调用,并输入ProcessingEnviroment参数。ProcessingEnviroment提供许多有效的工具类Elements, Types和Filer。
  • process(Set<? extends TypeElement> annotations, RoundEnvironment env): 这相称于每个处置惩罚器的主函数main()。你在这里写你的扫描、评估和处置惩罚注解的代码,以及生成Java文件。输入参数RoundEnviroment,可以让你查询出包罗特定注解的被注解元素。
  • getSupportedAnnotationTypes(): 这里你必须指定,这个注解处置惩罚器是注册给哪个注解的。留意,它的返回值是一个字符串的集合,包罗本处置惩罚器想要处置惩罚的注解范例的合法全称。换句话说,你在这里界说你的注解处置惩罚器注册到哪些注解上。
  • getSupportedSourceVersion(): 用来指定你使用的Java版本。通常这里返回SourceVersion.latestSupported()。然而,假如你有富足的来由只支持Java 6的话,你也可以返回SourceVersion.RELEASE_6。我保举你使用前者。
ProcessingEnvironment

ProcessingEnvironment对象是apt的核心工具类


获取Elements的范例
processingEnv.getElementUtils().getTypeElement(type).asType()输出调试日志
     processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING," test NativeProcessor");判定此元素的范例,做干系安全校验之类的
private boolean isSubtype(Element typeElement, String type) {  return processingEnv.getTypeUtils().isSubtype(typeElement.asType(),      processingEnv.getElementUtils().getTypeElement(type).asType());}返回用来创建类或者辅助文件的filer
  JavaFile javaFile = JavaFile.builder("com.example",userTypeSpec.build()).build();        try {            javaFile.writeTo(processingEnv.getFiler());        } catch (IOException e) {            e.printStackTrace();        }RoundEnvironment

public interface RoundEnvironment {    boolean processingOver();     //上一轮注解处置惩罚器是否产生错误    boolean errorRaised();     //返回上一轮注解处置惩罚器生成的根元素    Set<? extends Element> getRootElements();   //返回包罗指定注解范例的元素的集合    Set<? extends Element> getElementsAnnotatedWith(TypeElement a);    //返回包罗指定注解范例的元素的集合    Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a);}Element

element体现一个静态的,语言级别的构件。而任何一个布局化文档都可以看作是由差异的element构成的布局体,对java源文件来说
package com.closedevice;             //PackageElementpublic class Main{                  //TypeElement    private int x;                  //VariableElement    private Main(){                 //ExecuteableElement    }    private void print( //ExecuteableElement                              int msg                             ){ //VariableElement    }}Element代表步调元素:包,类,方法都是一种步调元素

5.png

  • VariableElement   代表一个 字段, 罗列常量, 方法或者构造方法的参数, 局部变量及 非常参数等元素
  • PackageElement    代表包元素
  • TypeElement   代表类或接口元素
  • ExecutableElement 代码方法,构造函数,类或接口的初始化代码块等元素,也包罗注解范例元素
public interface Element extends javax.lang.model.AnnotatedConstruct {  //返回一个TypeMirror元素的范例信息,包罗包名,类(或方法,或参数)  //名的范例,在生成动态代码的时间,我们通常必要知道变量/方法参数的类  //型  ,以便写入正确的范例声明    TypeMirror asType();   //返回element的范例,判定是哪种element    ElementKind getKind();   //获取修饰关键字,入public static final,abstract等关键字    Set<Modifier> getModifiers();   //获取名字,不带包名    Name getSimpleName();   //getEnclosedElements    Element getEnclosingElement();    //返回该元素直接包罗的子元素,通常对一个PackageElement而言,它可   //以包罗TypeElement;对于一个TypeElement而言,它大概包罗属性   //VariableElement,方法ExecutableElement    List<? extends Element> getEnclosedElements();    //获取该元素上的注解的范例信息    @Override    List<? extends AnnotationMirror> getAnnotationMirrors();   //获取该元素上的注解    @Override    <A extends Annotation> A getAnnotation(Class<A> annotationType);    @Override    <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType);}以上是Element的方法,同时它的子类有自己的方法
public interface ExecutableElement extends Element, Parameterizable {//用于获取方法的参数元素,每个元素是一个VariableElementList<? extends VariableElement> getParameters();//获取方法元素的返回值,返回范例TypeMirror体现TypeMirror getReturnType()}public interface VariableElement extends Element {//假如属性变量被final修饰,则可以使用该方法获取它的值Object getConstantValue();}public interface TypeElement extends Element, Parameterizable, QualifiedNameable {    //获取类全限定名   Name getQualifiedName();}ElementKind

public enum ElementKind {    /** A package. */    PACKAGE,    // Declared types    /** An enum class. */    ENUM,    /**     * A class not described by a more specific kind (like {@code     * ENUM} or {@code RECORD}).     */    CLASS,    /** An annotation interface. (Formerly known as an annotation type.) */    ANNOTATION_TYPE,    /**     * An interface not described by a more specific kind (like     * {@code ANNOTATION_TYPE}).     */    INTERFACE,    // Variables    /** An enum constant. */    ENUM_CONSTANT,    /**     * A field not described by a more specific kind (like     * {@code ENUM_CONSTANT}).     */    FIELD,    /** A parameter of a method or constructor. */    PARAMETER,    /** A local variable. */    LOCAL_VARIABLE,    /** A parameter of an exception handler. */    EXCEPTION_PARAMETER,    // Executables    /** A method. */    METHOD,    /** A constructor. */    CONSTRUCTOR,    /** A static initializer. */    STATIC_INIT,    /** An instance initializer. */    INSTANCE_INIT,    /** A type parameter. */    TYPE_PARAMETER,    /**     * An implementation-reserved element.  This is not the element     * you are looking for.     */    OTHER,    // Constants added since initial release    /**     * A resource variable.     * @since 1.7     */     RESOURCE_VARIABLE,    /**     * A module.     * @since 9     */     MODULE,    /**     * A record class.     * @since 16     */    RECORD,    /**     * A record component of a {@code record}.     * @since 16     */    RECORD_COMPONENT,    /**     * A binding variable in a pattern.     * @since 16     */    BINDING_VARIABLE;}Modifier

public enum Modifier {/** The modifier {@code public} */          PUBLIC,    /** The modifier {@code protected} */       PROTECTED,    /** The modifier {@code private} */         PRIVATE,    /** The modifier {@code abstract} */        ABSTRACT,    /**     * The modifier {@code default}     * @since 1.8     */     DEFAULT,    /** The modifier {@code static} */          STATIC,    /**     * The modifier {@code sealed}     * @since 17     */    SEALED,    /**     * The modifier {@code non-sealed}     * @since 17     */    NON_SEALED {        public String toString() {            return "non-sealed";        }    },    /** The modifier {@code final} */           FINAL,    /** The modifier {@code transient} */       TRANSIENT,    /** The modifier {@code volatile} */        VOLATILE,    /** The modifier {@code synchronized} */    SYNCHRONIZED,    /** The modifier {@code native} */          NATIVE,    /** The modifier {@code strictfp} */        STRICTFP;}TypeMirror接口

public interface TypeMirror extends javax.lang.model.AnnotatedConstruct {   //返回TypeKind范例,java语言中的范例.Types包罗基本范例,声明范例(类范例和接口类    //型),数组,范例变量和空范例 TypeKind getKind();   @Override    List<? extends AnnotationMirror> getAnnotationMirrors();    @Override    <A extends Annotation> A getAnnotation(Class<A> annotationType);    @Override    <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType);}public enum TypeKind {    /**     * The primitive type {@code boolean}.     */    BOOLEAN,    /**     * The primitive type {@code byte}.     */    BYTE,    /**     * The primitive type {@code short}.     */    SHORT,    /**     * The primitive type {@code int}.     */    INT,    /**     * The primitive type {@code long}.     */    LONG,    /**     * The primitive type {@code char}.     */    CHAR,    /**     * The primitive type {@code float}.     */    FLOAT,    /**     * The primitive type {@code double}.     */    DOUBLE,    /**     * The pseudo-type corresponding to the keyword {@code void}.     * @see NoType     */    VOID,    /**     * A pseudo-type used where no actual type is appropriate.     * @see NoType     */    NONE,    /**     * The null type.     */    NULL,    /**     * An array type.     */    ARRAY,    /**     * A class or interface type.     */    DECLARED,    /**     * A class or interface type that could not be resolved.     */    ERROR,    /**     * A type variable.     */    TYPEVAR,    /**     * A wildcard type argument.     */    WILDCARD,    /**     * A pseudo-type corresponding to a package element.     * @see NoType     */    PACKAGE,    /**     * A method, constructor, or initializer.     */    EXECUTABLE,    /**     * An implementation-reserved type.     * This is not the type you are looking for.     */    OTHER,    /**      * A union type.      *      * @since 1.7      */    UNION,    /**      * An intersection type.      *      * @since 1.8      */    INTERSECTION,    /**     * A pseudo-type corresponding to a module element.     * @see NoType     * @since 9     */    MODULE}代码示例

获取一个类注解的值,而且获取类内里的方法


  • 使用注解
@NativeAnnotation(path = " path hahaha")public class test {    public native int nativeInit(Fragment i, int j, String[] strings, ArrayList arrayList);}

  • process誊写逻辑
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {        //找出含有NativeAnnotation注解元素        Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(NativeAnnotation.class);        for (Element element : elements) {            //获取element元素上的注解            NativeAnnotation aah = element.getAnnotation(NativeAnnotation.class);            //获取注解的值            String path = aah.path();            processingEnv.getMessager().printMessage(                    Diagnostic.Kind.WARNING," value path : " +  path);            //判定是否是类注解            if (element.getKind() == ElementKind.CLASS) {                TypeElement typeElement = (TypeElement) element;                //获取全类名                String className = typeElement.getQualifiedName().toString();                processingEnv.getMessager().printMessage(                        Diagnostic.Kind.WARNING," className: " +  className);                //获取类内里的元素                List<? extends Element> elements1 = typeElement.getEnclosedElements();                for (Element element1 : elements1) {                    //判定元素是否是方法                    if (element1.getKind() == ElementKind.METHOD) {                        ExecutableElement executableElement = (ExecutableElement)element1;                        //打印方法名                        processingEnv.getMessager().printMessage                                (Diagnostic.Kind.WARNING," method : "                                         +  executableElement.getSimpleName());                        //打印方法返回值                        processingEnv.getMessager().printMessage                                (Diagnostic.Kind.WARNING," return : "                                         +  executableElement.getReturnType().toString());                        //打印方法修饰符                        processingEnv.getMessager().printMessage                                (Diagnostic.Kind.WARNING," Modifiers : "                                         +  executableElement.getModifiers().toString());                        //获取方法参数                        List<? extends VariableElement> variableElements = executableElement.getParameters();                        for (VariableElement element2 : variableElements) {                            //打印参数名称                            processingEnv.getMessager().printMessage                                    (Diagnostic.Kind.WARNING," Parame name: "                                            +  element2.getSimpleName());                            //打印参数范例                            processingEnv.getMessager().printMessage                                    (Diagnostic.Kind.WARNING," Parame TypeKind : "                                             +  element2.asType().getKind().name());                            //打印参数范例                            processingEnv.getMessager().printMessage                                    (Diagnostic.Kind.WARNING," Parame type : "                                             +  element2.asType().toString());                        }                    }                }            }        }}

  • 运行效果
value path :  path hahaha����:  className: com.example.annotationjnicheck.test����:  method : nativeInit����:  return : int����:  Modifiers : [public, native]����:  Parame name: i����:  Parame TypeKind : DECLARED����:  Parame type : android.app.Fragment����:  Parame name: j����:  Parame TypeKind : INT����:  Parame type : int����:  Parame name: strings����:  Parame TypeKind : ARRAY����:  Parame type : java.lang.String[]����:  Parame name: arrayList����:  Parame TypeKind : DECLARED����:  Parame type : java.util.ArrayList参考链接:
https://blog.csdn.net/heng615975867/article/details/105072317/
http://www.360doc.com/showweb/0/0/1036633837.aspx
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-11-21 22:02, Processed in 0.164135 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表