Android APT技术说明
1. Element和TypeMirror
1.1 Element
Element 代表程序的元素,在注解处理过程中,编译器会扫描所有的Java源文件,并将源码中的每一个部分都看作特定类型的 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
) {
}
}
Element接口方法如下:
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);
}
Element常用子类
PackageElement | 表示一个包程序元素 |
---|---|
TypeElement | 表示一个类或接口程序元素 |
VariableElement | 表示一个字段、enum 常量、方法或构造方法参数、局部变量或异常参数 |
ExecutableElement | 表示某个类或接口的方法、构造方法或初始化程序(静态或实例),包括注解类型元素 |
TypeParameterElement | 表示一般类、接口、方法或构造方法元素的泛型参数 |
/**
* 表示一个包程序元素.
*/
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();
}
源码中的每个部分都作为Element,每个Element 的种类需要通过getKind() 方法返回的ElementKind枚举值来判断
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称作元素的种类,因为它和元素的类型TypeMirror 比较容易混淆。TypeMirror表示的是 Java 编程语言中的类型 , 比如上面例子中的字段String name,它的元素种类为FIELD,而它的元素类型为DECLARED表示一个类类型,这里对应Java 编程语言中的类型为java.lang.String,Element代表的是源代码上的元素,TypeMirror代表的是Element对应Java 编程语言中的类型。
/**
* 表示 Java 编程语言中的类型
*/
public interface TypeMirror {
/**
* 返回此类型的种类,一个 TypeKind 枚举值:
*/
TypeKind getKind();
}
TypeKind 表示此元素在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;
}
TypeMirror的子类型如下:
ArrayType | 代表数组类型,可通过API获取元数据类型 |
---|---|
DeclaredType | 声明类型,即类或接口。可以通过asElement()和后面的Element进行转换 ,List<? extends TypeMirror> getTypeArguments() 该方法可以获取DeclaredType的泛型 |
ExecutableType | 构造器、初始化块等可执行体的类型,类似反射中Method,包含几个关键API:List<? extends TypeVariable> getTypeVariables()获取声明中的泛型、List<? extends TypeMirror> getParameterTypes()获取入参类型、TypeMirror getReturnType()获取返回值类型、List<? extends TypeMirror> getThrownTypes()获取声明的异常类型 |
TypeVariable | 可以通过getLowerBound()和getUpperBound()获取类型限定、 |
WildcardType | |
其他 | 用的不是很多,参考文档 |
DeclaredType
可以通过asElement()
方法转换为TypeElement
,getTypeArguments()
则可以获取相关的泛型参数,比如Map<String,String> map
,map
属于VariableElement
, 它的TypeMirror
属于DeclaredType, 因此可以转换为(typeMirror as DeclaredType).asElement() as TypeElement
,getTypeArguments()
获取Map的泛型
2. 注解
2.1 声明注解
//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 元注解
定义:用于解释注解的注解
常用元注解:
//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.自定义一个注解解析器
3.1 依赖配置
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 常用方法
@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{
}
最后
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓
PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题