注解处理器(Annotation Processor 是javac的一个工具,它是在编译时扫描注解和处理注解(Annotation)
可以自定义注解,并注册相应的注解处理器
在Andorid开源库中,有不少是使用到注解处理器的框架,像 Butterknife
,Dagger2
和路由ARouter
等等
依赖添加
随着 Android Gradle 插件 2.2 版本的发布, android-apt
作者声明后续将不会继续维护android-apt
,推荐使用 Android 官方插件提供的Android Gradle 插件的 annotationProcessor
功能来完全代替它
Android Gradle 插件 2.2 版本前:
//整个项目的build.gradle
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.5.0'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
//APP的build.gradle中
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
...
dependencies {
...
apt 'xx.xxx: xxx:1.0.0' //使用apt依赖项目
}
Android Gradle 插件 2.2 版本之后: 使用annotationProcessor 添加依赖项目
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])'
...
annotationProcessor project(':router-compiler')
}
创建相应的模块
名字随便起
1.创建一个annotation的java模块,创建需要用到的注解
比如:这里创建了两个注解:
@Target({ElementType.TYPE}) //注解使用范围,在class类上面使用
@Retention(RetentionPolicy.CLASS) //注解生命周期
public @interface Route {
}
2.创建一个compiler的java模块,在这个模块自定义注解处理器
这里自定义了一个对应上面Route
注解的注解处理器RouteProcessor
@AutoService(Processor.class) //自动注册
@SupportedOptions(Consts.ARGUMENTS_NAME) //处理器接受参数
@SupportedSourceVersion(SourceVersion.RELEASE_7) //指定java版本
@SupportedAnnotationTypes({Consts.ANN_TYPE_ROUTE}) //处理的注解
public class RouteProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
//编译期扫码到注解会调用到这里,在这里处理自动生成代码
return false;
}
}
@SupportedAnnotationTypes
注册给哪些注解使用的?等于AbstractProcessor#getSupportedAnnotationTypes() 方法
@SupportedSourceVersion
指定使用的Java版本AbstractProcessor#getSupportedSourceVersion()方法
@SupportedOptions
处理器接收的参数 替代 AbstractProcessor#getSupportedOptions()方法
@AutoService(Processor.class)
自动注册注解处理器
注解处理器是需要注册才会被识别使用的,所以需要在这个模块下添加google自动注册服务依赖, 如下:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.google.auto.service:auto-service:1.0-rc2' //自动注册注解处理器
implementation 'com.squareup:javapoet:1.7.0' //javapoet代码生成框架
implementation project(':router-annotation') //依赖注解模块
}
当编译期扫描到注解,就会调用RouteProcessor
的process
方法里面,在这里面处理自动生成代码的逻辑,可以使用javaPoet
框架来处理需要生成的代码格式.
JavaPoet是square推出的开源java代码生成框架,提供Java Api生成.java源文件
@AutoService(Processor.class)
@SupportedOptions(Consts.ARGUMENTS_NAME)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedAnnotationTypes({Consts.ANN_TYPE_ROUTE})
public class RouteProcessor extends AbstractProcessor {
private Filer filer;
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
filer = processingEnv.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();
// HelloWorld class
TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(main)
.build();
try {
// build com.example.HelloWorld.java
JavaFile javaFile = JavaFile.builder("com.example", helloWorld)
.addFileComment(" This codes are generated automatically. Do not modify!")
.build();
// write to file
javaFile.writeTo(filer);
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
生成的java文件会在使用该注解Route
的模块下的build目录下面:
生成.java内容如下:
package com.example;
import java.lang.String;
import java.lang.System;
public final class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, JavaPoet!");
}
}
这是一个简单的例子
apt注解处理器在项目的应用例子:
做一个自己简单的Router路由
更多使用的技巧可参考javapoet 的github:
https://github.com/square/javapoet#s-for-strings