APT学习的简单使用

2022-08-16  本文已影响0人  xyzkaye

APT介绍与使用

APT(Annotation Processing Tool)

是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,根据注解自动生成代码,如果想要自定义的注解处理器能够正常运行,必须要通过APT工具来进行处理。可以理解为,只有通过声明APT工具后,程序在编译期间自定义注解解释器才能执行。(APT编译时注解-是javac的一个工具 ,可以用来在编译期间扫描和处理注解,通过APT可以获取注解和备注解的相关信息,通过这些信息动态的生成代码省去手动编写。)

如经常使用的第三方库: ButterKnife,EventBus,Retrofit,ARouter等

如何构建一个APT项目

APT项目至少需要2个Java libaray组成。
1.首先需要Annotation模块,用来存放自定义注解。
2.另外需要一个Compiler模块,这个模块依赖Annotation模块。
3.项目的App模块和其它业务模块都需要依赖Annotation模块,同时需要通过annotationProcessor依赖Complier模块。
注意:android是基于openJDK,openJDK不包括APT的相关代码。因此APT必须在java libaray中进行。

//--------------结构体语音--------------
<html>//网页
    <body>
        <div>...</div>
    </dody>
</html>

// java源文件
package com.unisound.apt;                   // PackageElement  包元素/节点
public class main{                          // TypeElement  类元素/节点
    private int  x;                          // VariableElement   属性元素
    private main(){}                        // ExecuteableElement  方法元素
    private void init(String msg){}
}
Element程序元素

PackageElement
表示一个包程序元素。提供对有关包及其成员的信息的访问

ExecutableElement
表示某个类或接口的方法、构造方法或初始化程序 (静态或实例)

TypeElement
表示一个类或接口程序元素。提供对有关类型及其成员的信息的访问。

VariableElement
表示一个字段、enum 常量、方法或构造方法参数、局部变量或异常参数

// 常用的API
getEnclosedElements()       返回该元素直接包含的子元素

getKind()                   返回element的类型,判断是哪种element

getModifiers()              获取修饰关键字,入public static final等关键字

getSimpleName()             获取名字,不带包名

getQualifiedNamel)          获取全名,如果是类的话,包含完整的包名路径

getParameters()             获取方法的参数元素,每个元素是一个VariableElement

getReturnType()             获取方法元素的返回值

getConstantValuel)          如果属性变量被final修饰,则可以使用该方法获取它的值
 @Target(ElementType.TYPE)    // 接口、类、枚举、注解
 @Target(ElementType.FIELD)   // 属性、枚举的常量
 @Target(ElementType.METHOD)   // 方法
 @Target(ElementType.PARAMETER)  // 方法参数
 @Target(ElementType.CONSTRUCTOR)   // 构造函数
 @Target(ElementType.LOCAL_VARIABLE)  // 局部变量
 @Target(ElementType.ANNOTATION_TYPE)  // 该注解使用在另一个注解上
 @Target(ElementType.PACKAGE)        // 包

 @Retention(RetentionPolicy.RUNTIME) 注解会在class字节码文件中存在,jvm加载时可以通过反射获取到该注解的内容

  生命周期:SOURCE < CLASS < RUNTIME
  1、一般如果需要在运行时去动态获取注解信息,用RUNTIME注解
  2、要在编译时进行一些预处理操作,如ButterKnife,用CLASS注解。注解会在class文件中存在,但是在运行时会被丢弃
  3、做一些检查性的操作,如@Override,用SOURCE源码注解。注解仅存在源码级别,在编译的时候丢弃该注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface ARouter {
    // 详细路由路径 如 /app/MainActivity
    String path();
    // 路由组名 可以从path 中截取
    String group() default "";
}
dependencies { 
    compileOnly'com.google.auto.service:auto-service:1.0-rc4'
    annotationProcessor'com.google.auto.service:auto-service:1.0-rc4'

    // 引入annotation,让注解处理器-处理注解
    implementation project(':annotation')
}
// AutoService 是固定的写法,加个注解即可
// 通过auto-service中的@AutoService可以自动生成AutoService注解处理器,用来注册
// 用来生成 META-INF/services/javax.annotation.processing.Processor 文件
@AutoService(Processor.class)
// 允许/支持 的注解类型,让注解处理器处理(新增annotation module)
@SupportedAnnotationTypes({"com.xxx.annotation.ARouter"})
// 指定JDK编译版本
@SupportedSourceVersion(SourceVersion.RELEASE_7)
// 注解处理器接收的参数
@SupportedOptions("content")
public class ARouterProcessor extends AbstractProcessor {
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnv) {
// 可参考 EventBus(https://github.com/greenrobot/EventBus)
    }
}
        // 在gradle文件中配置选项参数值(用于APT传参接收)
        // 切记:必须写在defaultConfig节点下
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [content : 'hello apt']
            }
        }

// java控制台输出中文乱码
tasks.withType(JavaCompile) {
    options.encoding = "UTF-8"
}

APT高级用法JavaPoet
https://github.com/square/javapoet

    // 帮助我们通过类调用的形式来生成Java代码
    implementation "com.squareup:javapoet:1.9.0"
上一篇 下一篇

猜你喜欢

热点阅读