美文网首页
APT注解处理

APT注解处理

作者: waiwaaa | 来源:发表于2020-03-31 17:53 被阅读0次

什么是APT?

APT(Annotation Processing Tool)注解处理工具,它是jdk提供的一套工具,通过这套工具我们可以在编译时,根据注解自动生成Java代码。

注解

注解可以理解为代码的标识,不会对运行有直接影响。

1、内置注解

Java内置几个常用注解,这部分标识源码,会被编译器识别,提示错误等。

@Override 标记覆盖方法
@Deprecated 标记为过时
@SuppressWarnings 忽略警告

2、元注解

假设我们要自定义一个注解,这时候就需要用元注解去声明自定义注解,包括像注解作用域、生命周期等。

@Documented 可以被javadoc文档化。
@Target 注解用在哪
CONSTRUCTOR 构造函数
FIELD 域声明
LOCAL_VARIABLE 局部变量
METHOD 方法
PACKAGE 包声明
PARAMETER 参数
TYPE 类、接口
@Inherited
允许子类继承父类注解
@Retention
SOURCE:编译时剔除
CLASS:在CLASS文件保留标识,运行时剔除
RUNTIME 运行时保留标识

3、自定义注解

使用元注解创建自定义注解

//直到运行时还保留注解
@Retention(RetentionPolicy.RUNTIME)
//作用域 类
@Target(ElementType.TYPE)
public @interface BindV {
    int resId() default 0;
}

4、解析注解

在代码中定义了标识,现在想拿到这些信息,可以通过反射、APT获取注解的值。

1、反射

通过反射解析注解(这里也不阐述什么是反射)

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ReadAnnotation {
    String value() default "read annotation defalult";
}
//MainActivity.java 文件
@ReadAnnotation("test")
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Class clz = MainActivity.class;
        ReadAnnotation read = (ReadAnnotation) clz.getAnnotation(ReadAnnotation.class);//反射拿到类的注解
        TextView textview=findViewById(R.id.txt);
        textview.setText(read.value());
    }
}

2、APT

APT(Annotation Processing Tool)注解处理器,是在编译期间读取注解,生成Java文件。反射解析注解是损耗性能的,接下来通过APT来生成java源码,从而避免反射。

1. 在之前的项目lib_annotation上创建新的注解AptTest

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface AptTest {
    String value() default "atp default String";
}

2. 创建注解处理(java)项目 lib_compiler

原理为通过获取注解参数,通过拼接字符串方式生成代码,然后写入文件。通过javapeat可以减少导包等操作。

@SupportedAnnotationTypes({"com.yy.lib_annotation.AptTest"})//声明需要匹配的注解
@SupportedSourceVersion(SourceVersion.RELEASE_8)//支持的Java版本
public class AptProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {


        Set<? extends Element> element = roundEnvironment.getElementsAnnotatedWith(AptTest.class);
        StringBuilder sb=new StringBuilder("all aptTest values is:");
        for (Element ele:element) {
            TypeElement typeelement = (TypeElement) ele;
            AptTest aptTest=typeelement.getAnnotation(AptTest.class);
            sb.append(aptTest.value());
            sb.append("|");
        }

        //新建一个方法
        MethodSpec getString = MethodSpec.methodBuilder("getString")
                .addModifiers(Modifier.PUBLIC)
                .returns(String.class)
                .addCode("return \""+sb.toString()+"\";\n")
                .build();
        //新建一个类
        TypeSpec testType = TypeSpec.classBuilder("APTTest").addModifiers(Modifier.PUBLIC).addMethod(getString).build();

        //生成这个类
        JavaFile javaFile = JavaFile.builder("com.yy.aptdemo", testType)
                .build();
        try {
            javaFile.writeTo(processingEnv.getFiler());
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println(e);
        }

        return true;
    }
}

项目结构变为


项目结构

3. lib_compiler注册处理器

gradle4可以直接用auto-service注解进行自动注册,现在新建的是gradle版本是5以上的,所以要手动注册,手动注册方法如下:
创建一个
META-INF/services/javax.annotation.processing.Processor文件,
其内容是一系列的自定义注解处理器完整有效类名集合,以换行切割:

com.yy.lib_compiler.AptProcessor

4.引入运行项目
在app项目中,
在build.gradle文件中引入

dependencies {
    implementation project(path: ':lib_annotation')
    annotationProcessor project(path: ':lib_compiler')
}

修改MainActivity

@ReadAnnotation("test")
@AptTest("this is apt from annotation")
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Class clz = MainActivity.class;
        ReadAnnotation read = (ReadAnnotation) clz.getAnnotation(ReadAnnotation.class);//拿到布局文件id
        TextView textview=findViewById(R.id.txt);
        textview.setText(read.value());

        //
        textview.setOnClickListener(view -> Toast.makeText(MainActivity.this,new APTTest().getString(),Toast.LENGTH_SHORT).show());
    }
}

运行,点击就可以得到AptTest的内容,同时我们可以在看到生成的类


apt生成的类文件

外记:有时我们生成的文件不同项目传入不同参数,可以在项目的build.gradle文件中配置能数

 compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
            javaCompileOptions.annotationProcessorOptions.arguments=[prjKey:project.getName()]//传入参数
        }

在处理器中类增加注解

@SupportedOptions("prjKey")//指定可以接收从build.gradle中传过来的参数prjKey

就可以得到传入的参数

@Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        Map<String, String> opts = processingEnvironment.getOptions();
        prjKey=opts.get("prjKey");
    }

本文示例代码已传至github

相关文章

网友评论

      本文标题:APT注解处理

      本文链接:https://www.haomeiwen.com/subject/ejywuhtx.html