Android APT basics and practice

Android APT technical description

1. Element and TypeMirror

1.1 Element

Element represents the element of the program. During annotation processing, the compiler scans all Java source files and regards each part of the source code as a specific type of Element

package com.example;        // PackageElement

import java.util.List;

public class Sample         // TypeElement
        <T extends List> {
    
      // TypeParameterElement

    private int num;        // VariableElement
    String name;            // VariableElement

    public Sample() {
    
    }      // ExecuteableElement

    public void setName(    // ExecuteableElement
            String name     // VariableElement
            ) {
    
    }
}

The Element interface method is as follows:

public interface Element extends AnnotatedConstruct{
    
    
    /**
     * 返回此元素定义的类型
     * 例如,对于一般类元素 C<N extends Number>,返回参数化类型 C<N>
     */
    TypeMirror asType();

    /**
     * 返回此元素的种类:包、类、接口、方法、字段...,如下枚举值
     * PACKAGE, ENUM, CLASS, ANNOTATION_TYPE, INTERFACE, ENUM_CONSTANT, FIELD, PARAMETER, LOCAL_VARIABLE, EXCEPTION_PARAMETER,
     * METHOD, CONSTRUCTOR, STATIC_INIT, INSTANCE_INIT, TYPE_PARAMETER, OTHER, RESOURCE_VARIABLE;
     */
    ElementKind getKind();

      /**
     * 返回此元素的修饰符,如下枚举值
     * PUBLIC, PROTECTED, PRIVATE, ABSTRACT, DEFAULT, STATIC, FINAL,
     * TRANSIENT, VOLATILE, SYNCHRONIZED, NATIVE, STRICTFP;
     */
    Set<Modifier> getModifiers();


    /**
     * 返回此元素的简单名称,例如
     * 类型元素 java.util.Set<E> 的简单名称是 "Set";
     * 如果此元素表示一个未指定的包,则返回一个空名称;
     * 如果它表示一个构造方法,则返回名称 "<init>";
     * 如果它表示一个静态初始化程序,则返回名称 "<clinit>";
     * 如果它表示一个匿名类或者实例初始化程序,则返回一个空名称
     */
    Name getSimpleName();


     /**
     * 返回封装此元素的最外层元素。比如TypeElement 返回packageelemnet
     * ExecutableElement返回typeElement,VariableElement返回TypeElement(全局Field)或者
     * ExecutableElement(局部Field)
     * 如果此元素的声明在词法上直接封装在另一个元素的声明中,则返回那个封装元素;
     * 如果此元素是顶层类型,则返回它的包;
     * 如果此元素是一个包,则返回 null;
     * 如果此元素是一个泛型参数,则返回 null.
     */
    Element getEnclosingElement();

     /**
     * 返回此元素直接封装的子元素,与getEnclosingElemen()相反,packageElement返回
     * TypeElement,TypeElement返回ExecutableElement和
     */
    List<? extends Element> getEnclosedElements();

    /**
     * 返回直接存在于此元素上的注解
     * 要获得继承的注解,可使用 getAllAnnotationMirrors
     */
    @Override
    List<? extends AnnotationMirror> getAnnotationMirrors();

    /**
     * 返回此元素针对指定类型的注解(如果存在这样的注解),否则返回 null。注解可以是继承的,也可以是直接存在于此元素上的
     */
    @Override
    <A extends Annotation> A getAnnotation(Class<A> annotationType);

}

Commonly used subclasses of Element

PackageElement Represents a package program element
TypeElement Represents a class or interface program element
VariableElement Represents a field, enum constant, method or constructor parameter, local variable or exception parameter
ExecutableElement Represents a method, constructor, or initializer (static or instance) of a class or interface, including annotation type elements
TypeParameterElement A generic parameter representing a generic class, interface, method, or constructor element
/**
 * 表示一个包程序元素.
 */
public interface PackageElement {
    
    

    /**
     * 返回此包的完全限定名称。该名称也是包的规范名称
     */
    Name getQualifiedName();

    /**
     * 如果此包是一个未命名的包,则返回 true,否则返回 false
     */
    boolean isUnnamed();
}
/**
 * 表示某个类或接口的方法、构造方法或初始化程序(静态或实例),包括注解类型元素
 */
public interface ExecutableElement {
    
    

    /**
     * 获取按照声明顺序返回形式类型参数元素
     */
    List<? extends TypeParameterElement> getTypeParameters();

    /**
     * 获取返回的类型元素
     */
    TypeMirror getReturnType();

    /**
     * 获取形参元素
     */
    List<? extends VariableElement> getParameters();


     /**
     * 如果此方法或构造方法接受可变数量的参数,则返回 true,否则返回 false
     */
    boolean isVarArgs();

    /**
     * 按声明顺序返回此方法或构造方法的 throws 子句中所列出的异常和其他 throwable
     */
    List<? extends TypeMirror> getThrownTypes();

    /**
     * 如果此 executable 是一个注解类型元素,则返回默认值。如果此方法不是注解类型元素,或者它是一个没有默认值的注解类型元素,则返回 null
     */
    AnnotationValue getDefaultValue();
}
/**
 * 表示一个字段、enum 常量、方法或构造方法参数、局部变量或异常参数
 */
public interface VariableElement {
    
    

    /**
     * 如果此变量是一个被初始化为编译时常量的 static final 字段,则返回此变量的值。否则返回 null。
     * 该值为基本类型或 String,如果该值为基本类型,则它被包装在适当的包装类中(比如 Integer)。
     * 注意,并非所有的 static final 字段都将具有常量值。特别是,enum 常量不 被认为是编译时常量。要获得一个常量值,字段的类型必须是基本类型或 String
     */
    Object getConstantValue();
}
/**
 * 表示一般类、接口、方法或构造方法元素的泛型参数
 */
public interface TypeParameterElement {
    
    

    /**
     * 返回由此类型参数参数化的一般类、接口、方法或构造方法
     */
    Element getGenericElement();

    /**
     * 返回此类型参数的边界。它们是用来声明此类型参数的 extends 子句所指定的类型。
     * 如果没有使用显式的 extends 子句,则认为 java.lang.Object 是唯一的边界
     */
    List<? extends TypeMirror> getBounds();
}

Each part of the source code is an Element, and the type of each Element needs to be judged by the ElementKind enumeration value returned by the getKind() method

public enum ElementKind {
    
    

    /** A package. */
    PACKAGE,
    /** An enum tye. */
    ENUM,
    /** A class not described by a more specific kind (like {@code ENUM}). */
    CLASS,
    /** An annotation type. */
    ANNOTATION_TYPE,
    /** An interface not described by a more specific kind */
    INTERFACE,

    // Variables
    /** An enum constant. */
    ENUM_CONSTANT,
    /** A field not described by a more specific kind */
    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,
    /**
     * A resource variable.
     * @since 1.7
     */
    RESOURCE_VARIABLE;
}

1.2 TypeMirror

ElementKind is called the type of element because it is more confusing with the type of element TypeMirror . TypeMirror represents the type in the Java programming language, such as the field String name in the above example , its element type is FIELD , and its element type is DECLARED to represent a class type, which corresponds to the type in the Java programming language as java. lang.String , Element represents the element on the source code, and TypeMirror represents the type in the Java programming language corresponding to Element .

/**
 * 表示 Java 编程语言中的类型
 */
public interface TypeMirror {
    
    
    /**
     * 返回此类型的种类,一个 TypeKind 枚举值:
     */
    TypeKind getKind();
}

TypeKind indicates the type of this element in java

public enum TypeKind {
    
    
    /** The primitive type {@codeoolean}. */
    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}. */
    VOID,
    /** A pseudo-type used where no actual type is appropriate. */
    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. */
    PACKAGE,
    /** A method, constructor, or initializer. */
    EXECUTABLE,
    /** An implementation-reserved type. This is not the type you are looking for. */
    OTHER,
    /** A union type. */
    UNION,
    /** An intersection type. */
    INTERSECTION;
}

The subtypes of TypeMirror are as follows:

ArrayType Represents the array type, and the metadata type can be obtained through the API
DeclaredType Declare the type, i.e. class or interface. It can be converted by asElement() and the following Element, List<? extends TypeMirror> getTypeArguments()which can obtain the generic type of DeclaredType
ExecutableType The types of executables such as constructors and initialization blocks, similar to Method in reflection, include several key APIs: List<? extends TypeVariable> getTypeVariables() to get the generic type in the declaration, List<? Parameter type, TypeMirror getReturnType() to get the return value type, List<? extends TypeMirror> getThrownTypes() to get the declared exception type
TypeVariable Type limits can be obtained through getLowerBound() and getUpperBound(),
WildcardType
other Not used a lot, refer to the documentation

DeclaredTypeasElement()Can be converted to by method TypeElement, getTypeArguments()then you can get related generic parameters, for example Map<String,String> map, mapbelongs to VariableElement, it TypeMirrorbelongs to DeclaredType, so it can be converted to (typeMirror as DeclaredType).asElement() as TypeElement, getTypeArguments()get the generic type of Map

2. Notes

2.1 Declaration Notes
//java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface RetrofitService {
    
    
    String name() default "";
}
//kotlin
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS)
annotation class ServiceRepository(val altName: String = "")

2.2 Meta annotations

Definitions: Annotations used to explain annotations

Common meta annotations:

//1.@Target 表示这个注解(作用于)可以放到什么位置上面
/**
 * ElementType.ANNOTATION_TYPE //能修饰注解
 * ElementType.CONSTRUCTOR //能修饰构造器
 * ElementType.FIELD //能修饰成员变量
 * ElementType.LOCAL_VARIABLE //能修饰局部变量
 * ElementType.METHOD //能修饰方法
 * ElementType.PACKAGE //能修饰包名
 * ElementType.PARAMETER //能修饰参数
 * ElementType.TYPE //能修饰类、接口或枚举类型
 * ElementType.TYPE_PARAMETER //能修饰泛型,如泛型方法、泛型类、泛型接口 (jdk1.8加入)
 * ElementType.TYPE_USE //能修饰类型 可用于任意类型除了 class (jdk1.8加入)
 *
 */

//2.@Retention 表示注解的的生命周期
/**
 * RetentionPolicy.SOURCE //表示注解只在源码中存在,编译成 class 之后,就没了
 * RetentionPolicy.CLASS //表示注解在 java 源文件编程成 .class 文件后,依然存在,但是运行起来后就没了
 * RetentionPolicy.RUNTIME //表示注解在运行起来后依然存在,程序可以通过反射获取这些信息
 */

/**
*3.@Inherited  @Inherited 表示该注解可被继承,即当一个子类继承一个父类,
*该父类添加的注解有被 @Inherited 修饰,那么子类就可以获取到该注解,否则获取不到
*/

/**
*
*4.@Documented 表示该注解在通过 javadoc 命令生成 Api 文档后,会出现该注解的注释说明
*/

/**
*
*5.@Repeatable 是 JDK 1.8 新增的元注解,它表示注解在同一个位置能出现多次
*/

3. Customize an annotation parser

3.1 Dependency configuration
dependencies {
    
    

    implementation project(':apt_annotations') // 依赖注解project

    api project(':http_network')

    implementation "org.jetbrains.kotlin:kotlin-stdlib:1.6.0"

    //用于启动自定义的processor,implementation和kapt auto-service
    implementation 'com.google.auto.service:auto-service:1.0-rc2'
    kapt 'com.google.auto.service:auto-service:1.0-rc2'

//    implementation "com.google.auto.service:auto-service:1.0"
//    kapt "com.google.auto.service:auto-service:1.0"
    //kotlinpoet,看需求也可以使用javapoet
    implementation "com.squareup:kotlinpoet:1.12.0"  
}

3.2 Common methods
@AutoService(Processor::class) //启动ServiceRepositoryProcessor
class ServiceRepositoryProcessor : AbstractProcessor(){
    
    

   private val projectNameKey = "projectName"

   //初始化方法,可以在该方法获取三个工具类对象实例 
   override fun init(processingEnv: ProcessingEnvironment?) {
    
    
        super.init(processingEnv)
        elementUtil = processingEnv!!.elementUtils //element处理工具
        filerUtil = processingEnv.filer //代码文件生成工具
        messager = processingEnv.messager //消息打印工具
    }

    //该自定义注解处理的注解类型,系统编译期间会对应注解丢给该自定义注解器处理
    override fun getSupportedAnnotationTypes(): MutableSet<String> {
    
    
        return mutableSetOf<String>().apply {
    
    
            add(ServiceRepository::class.java.canonicalName)
        }
    }

     //可配置的参数 
    /**
     * kapt {
     *  arguments {
     *  arg("projectName", "xxxx")
     *    }
     *  }
    */
    //在process()方法中 String xxxxValue = processingEnv.getOptions().get(projectNameKey);
     override fun getSupportedOptions(): MutableSet<String> {
    
    
        return mutableSetOf<String>().apply {
    
    
            add(projectNameKey)
        }
    }

    //支持的jdk版本
    override fun getSupportedSourceVersion(): SourceVersion {
    
    
        return SourceVersion.latestSupported()
    }


     // return true 表示getSupportedAnnotationTypes中的注解在那个处理器内处理完成
     // return false 表示会继续向下一个processor中传递getSupportedAnnotationTypes中注解数据
     override fun process(
        typeElements: MutableSet<out TypeElement>?,
        roundEnvironment: RoundEnvironment?
    ): Boolean{
    
    

     }

at last

If you want to become an architect or want to break through the 20-30K salary range, then don't be limited to coding and business, but you must be able to select models, expand, and improve programming thinking. In addition, a good career plan is also very important, and the habit of learning is very important, but the most important thing is to be able to persevere. Any plan that cannot be implemented consistently is empty talk.

If you have no direction, here I would like to share with you a set of "Advanced Notes on the Eight Major Modules of Android" written by the senior architect of Ali, to help you organize the messy, scattered and fragmented knowledge systematically, so that you can systematically and efficiently Master the various knowledge points of Android development.
img
Compared with the fragmented content we usually read, the knowledge points of this note are more systematic, easier to understand and remember, and are arranged strictly according to the knowledge system.

Welcome everyone to support with one click and three links. If you need the information in the article, you can directly scan the CSDN official certification WeChat card at the end of the article to get it for free↓↓↓

PS: There is also a ChatGPT robot in the group, which can answer your work or technical questions
picture

Guess you like

Origin blog.csdn.net/YoungOne2333/article/details/132027651
Recommended