[TOC]

JavaPoet

JavaPoet是Square推出的开源Java代码生成框架,提供Java Api生成.java源文件。通过这个框架可以很方便的使用它根据注解、数据库模式、协议格式等来对应生成代码。用这种自动化生产代码的方式可以来替换冗杂重复的工作,提高工作效率。

代码生成技术相当于元编程,可用于编译期根据注解等元数据动态生成Java类。在框架Dagger、ButterKnife等等中就是利用JavaPoet注解的方式实现生成所需的类。

常用类

  • JavaFile:用于构造输出包含一个顶级类的Java文件,是对.java文件的抽象;
  • TypeSpec:TypeSpec是类/接口/枚举的抽象;
  • MethodSpec:MethodSpec是方法/构造函数的抽象;
  • FieldSpec:FieldSpec是成员变量/字段的抽象;
  • ParameterSpec:ParameterSpec用于创建参数;
  • AnnotationSpec:AnnotationSpec用于创建注解;
  • TypeName:类型;
  • ClassName:用来包装一个类;

占位符

  • $L 参数,方法中的参数;
  • $S 字符串,和String.format中%s一样;
  • $N 方法或变量的名称,我们自己生成的方法名或者变量名等等;
  • $T 类型名,指的是TypeName,该模板主要将Class抽象出来,用传入的TypeName指向的Class来代替;

设置方法抛出异常,可以使用addException方法,传入指定的异常的ClassName,即可为该方法设置其抛出该异常.

步骤

添加依赖

compileOnly 'com.google.auto.service:auto-service:1.0-rc4'
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
implementation 'com.squareup:javapoet:1.12.1'

一般情况下,还需要配合注解解释器来使用才行,一般我们常用的或注解解释器为 AutoService 和 gradle-incap-helper。

自定义处理器

注解处理器(Annotation Processor)是javac的一个工具,它用来在编译时扫描和处理注解(Annotation)。你可以自定义注解,并注册相应的注解处理器(自定义的注解处理器需继承自AbstractProcessor)。

注意:注解处理器是运行在独立的虚拟机JVM中,javac启动一个完整Java虚拟机来运行注解处理器。

相关方法
  • init(ProcessingEnvironment env): 初始化方法,会被注解处理器调用,可以从ProcessingEnviroment对象中获取到如Elements, Types,Messager和Filer等工具类;
  • process(Set< ? extends TypeElement> annotations, RoundEnvironment env): 真正的处理方法,也是核心的方法。在这里写如何处理注解的代码,以及生成的java文件需要存放的位置。参数RoundEnviroment可以查询出包含特定注解的被注解元素。
  • getSupportedAnnotationTypes(): 指定注解处理器是注册给哪个注解的。返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称。
  • getSupportedSourceVersion(): 用来指定你使用的Java版本。通常返回SourceVersion.latestSupported()。

技巧:后面两个方法还有另一种写法(通过注解给定)

@SupportedAnnotationTypes({Constants.BINDERVIEW_ANNOTATION_TYPES})
@SupportedSourceVersion(SourceVersion.RELEASE_7)

实现

@AutoService(Processor.class)
@SupportedAnnotationTypes(Constant.ANY_TYPE)
public class CustomProcessor extends AbstractProcessor {
private Filer filer;

@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
filer = processingEnvironment.getFiler();
}

@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
MethodSpec main = MethodSpec.methodBuilder("main")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(void.class)
.addParameter(String[].class, "args")
.addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
.build();

TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(main)
.build();

JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld).build();

try {
javaFile.writeTo(filer);
} catch (IOException e) {
e.printStackTrace();
}
return false;
}

@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.RELEASE_7;
}

@Override
public Set<String> getSupportedAnnotationTypes() {
return super.getSupportedAnnotationTypes();
}
}

思考

kapt和transform的差别

AbstractProcessor只能处理注解,然后根据注解通过javapoet生成一个新的java类。而transfrom则是通过gradle插件的transfrom方法,对.class文件做的修改。

AbstractProcessor是一个抽象类,它的父类是Processer。Processor会在编译阶段初始化,然后对当前模块内的代码进行一次扫描,然后获取到对应的注解,之后调用process方法,然后我们根据这些注解类来做一些后续操作。

编译过程

source(源代码) -> processor(处理器) -> generate (文件生成)-> javacompiler -> .class文件 -> .dex(只针对安卓)。

官方链接:https://github.com/square/javapoet