APT黄金搭档JavaPoet,让框架更稳定更简洁

什么是JavaPoet

项目主页及源码:https://github.com/square/javapoet

APT + JavaPoet = 超级利刃

JavaPoet是square推出的开源java代码生成框架,提供Java Api生成.java源文件,这个框架功能非常实用,也是我们习惯的Java面向对象OOP语法,可以很方便的使用它根据注解生成相应的代码,通过这种自动化生成代码的方式,可以让我们更加简洁优雅的方式要替代繁琐冗杂的重复工作(常规的通过继承注解处理器AbstractProcessor,根据注解生成java代码的时候,需要一行一行的进行字符串的拼接,如果生成java文件内容较多,实在是不优雅,可以说是不人性)。

依赖JavaPoet库

Android Studio 3.4.2 + Gradle5.1.1 (向下兼容)

compileOnly ‘com.google.auto.service:auto-service:1.0-rc4’
annotationProcessor ‘com.google.auto.service:auto-service:1.0-rc4’

依赖

//帮助我们通过类调用的形式来生成java代码

implementation ‘com.squareup:javapoet:1.9.0’

JavaPoet的8个常用类

注意与APT中结构体语言表述区别

类对象 说明
MethodSpec 代表一个构造函数或方法说明
TypeSpec 代表一个类,接口,或者枚举声明
FieldSpec 代表一个成员变量,一个字段声明
JavaFIle 包含一个顶级类的Java文件
ParameterSpec 用来创建参数
AnnotationSpec 用来创建注解
ClassName 用来包装一个类
TypeName 类型,如在添加返回值类型是使用TypeName.VOID

JavaPoet字符串格式化规则

L i n t v a l u e = L:字面量,如:“int value= L”,10

S S:字符串,如: S, “hello”

T T:类、接口,如: T,MainActivity

N v o i d g e t ( S t r i n g n a m e ) . . . n a m e N:变量,如:void get(String name){...} ,在方法中用到name时,可以用 N来表示(可以理解为占位符)

通过AbstractProcessor生成代码对比

传统方式

//触发注解处理器生成java文件
@AutoService(Processor.class)
//允许/支持的注解类型,让注解处理器处理
@SupportedAnnotationTypes({Constants.AROUTER_ANNOTATION_TYPE})
//指定JDK编译版本
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class ARouterProcessor extends AbstractProcessor {

    //Messager用来报告错误,警告和其它提示信息
    private Messager messager;
    //Elements中包含用于操作Element的工具方法
    private Elements elementUtils;
    //Filter用来创建新的源文件,类文件以及辅助文件
    private Filer filer;
    //Types中包含用于操作TypeMirror的工具方法
    private Types typeUtils;

    /**
     * 初始化操作,通过ProcessingEnvironment可以获取一系列有用的工具类
     * @param processingEnv
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        //初始化
        elementUtils = processingEnv.getElementUtils();
        typeUtils = processingEnv.getTypeUtils();
        filer = processingEnv.getFiler();
        messager = processingEnv.getMessager();
        messager.printMessage(Diagnostic.Kind.NOTE,
                "注解处理器初始化完成,开始处理注解......");
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnv) {
        if (set.isEmpty()) return false;
        //获取所有带@ARouter注解的类节点
        Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(ARouter.class);
        //遍历所有类节点
        for (Element element : elements) {
            //通过类节点获取包节点(全路径:com.example.xxx)
            String packageName = elementUtils.getPackageOf(element).getQualifiedName().toString();
            //获取简单类名
            String className = element.getSimpleName().toString();
            messager.printMessage(Diagnostic.Kind.NOTE, "被注解的类有:" + className);
            //最终想生成的类文件名
            String finalClassName = className + "$$ARouter";
            //常规写法,也是EventBus写法(https://github.com/greenrobot/EventBus)
            try {
                //创建一个新的源文件,并返回一个对象以允许写入它
                JavaFileObject sourceFile = filer.createSourceFile(packageName + "." + finalClassName);
                //定义Writer对象,开启写入
                Writer writer = sourceFile.openWriter();
                //设置包名
                writer.write("package " + packageName + ";\n");
                writer.write("import android.util.Log;\n");
                writer.write("public class " + finalClassName + "{\n");
                writer.write("public void hello(String path) {");
                writer.write("Log.d(\"xpf >>> \", \"APT......\");\n}\n");
                writer.write("\n}");
                //最后结束别忘了
                writer.close();

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return true;
    }
}

生成的java文件

package com.example.apt_javapoet;

import android.util.Log;

public class MainActivity$$ARouter {
    public void hello(String path) {
        Log.d("xpf >>> ", "APT......");
    }

}

采用JavaPoet方式

//触发注解处理器生成java文件
@AutoService(Processor.class)
//允许/支持的注解类型,让注解处理器处理
@SupportedAnnotationTypes({Constants.HELLOWORLD_ANNOTATION_TYPE})
//指定JDK编译版本
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class HelloWorldProcessor extends AbstractProcessor {

    //Messager用来报告错误,警告和其它提示信息
    private Messager messager;
    //Elements中包含用于操作Element的工具方法
    private Elements elementUtils;
    //Filter用来创建新的源文件,类文件以及辅助文件
    private Filer filer;
    //Types中包含用于操作TypeMirror的工具方法
    private Types typeUtils;

    /**
     * 初始化操作,通过ProcessingEnvironment可以获取一系列有用的工具类
     * @param processingEnv
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        //初始化
        elementUtils = processingEnv.getElementUtils();
        typeUtils = processingEnv.getTypeUtils();
        filer = processingEnv.getFiler();
        messager = processingEnv.getMessager();
        messager.printMessage(Diagnostic.Kind.NOTE,
                "注解处理器初始化完成,开始处理注解......");
    }


    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnv) {
        if (set.isEmpty()) return false;
        //获取所有被@HelloWorld注解的元素(方法)集合
        Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(HelloWorld.class);
        if (!elements.isEmpty()) {
            //解析元素,生成类文件
            //方法体
            MethodSpec main = MethodSpec.methodBuilder("main")//方法名
                    .addModifiers(Modifier.PUBLIC,Modifier.STATIC)//方法修饰符
                    .returns(void.class)//方法返回值(默认void)
                    .addParameter(String[].class, "args")//方法参数
                    .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")//方法内容
                    .build();//构建

            //类
            TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")//类名
                    .addModifiers(Modifier.PUBLIC)//类修饰符
                    .addMethod(main)//加入方法体
                    .build();//构建

            //文件生成器
            JavaFile javaFile = JavaFile.builder("com.example.helloWorld", helloWorld)
                    .build();

            //写文件
            try {
                javaFile.writeTo(filer);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return true;
    }
}

生成的java文件

package com.example.helloWorld;

import java.lang.String;
import java.lang.System;

public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello, JavaPoet!");
  }
}

一对比就知道差别了,省去了惨无人道的字符串拼接操作,谁用谁知道。

原创文章 23 获赞 30 访问量 9562

猜你喜欢

转载自blog.csdn.net/my_csdnboke/article/details/104880316