自动生成代码工具--APT
APT(Annotation Processing Tool)注解处理器,是javac的一个工具,它用来在编译时扫描和处理注解(Annotation)。它可以生成Java代码,同时这些代码会跟手工白那些的Java的代码一样被Javac编译。
虚处理器(javax.annotation.processing.AbstractProcessor)
每个处理器都继承自AbstractProcessor,相关Api如下:
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
public class MyProcessor extends AbstractProcessor {
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
return false;
}
@Override
public Set<String> getSupportedAnnotationTypes() {
return super.getSupportedAnnotationTypes();
}
@Override
public SourceVersion getSupportedSourceVersion() {
return super.getSupportedSourceVersion();
}
@Override
public Set<String> getSupportedOptions() {
return super.getSupportedOptions();
}
}
1、 init(ProcessingEnvironment processingEnvironment):processingEnvironment提供很多有用的工具类Elements、Types、Messager、Filer等
2、 process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment):相当于每个处理器的主函数main(),可以扫描出包含特定注解的被注解元素并生成想要的java文件
3、 getSupportedAnnotationTypes():需要你指定这个注解处理器是注册给那个注解的,即注解器处理的哪些注解
4、 getSupportedSourceVersion() :指定的java版本,通过建议是SourceVersion.latestSupported(),也可以指定某个版本,例如:SourceVersion.RELEASE_7
5、 getSupportedOptions():指定支持的选项参数名称,可以通过ProcessingEnvironment.getOptions()获取参数选项值
在Java7中,可以通过注解代替getSupportedAnnotationTypes()、getSupportedSourceVersion()、getSupportedOptions(),如下:
@SupportedAnnotationTypes({
//合法注解全名的结合
})
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedOptions({
//支持参数选项的key集合
})
public class MyProcessorextends AbstractProcessor {
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
return false;
}
}
因为兼容的原因,特别是针对Android平台 , 建议使用重载getSupportedAnnotationTypes()
和getSupportedSourceVersion()
方法代替@SupportedAnnotationTypes
和@SupportedSourceVersion
注册你的注解处理器
如何把自己的注解处理器注册到javac中,需要提供一个.jar包,并且在包中需要一个特定的文件javax.annotation.processing.Processor在META-INF/services路径下,所以.jar包看起来如下:
打进.jar包中的javax.annotation.processing.Processor内容是注解处理器的全名,可以多个处理器,每个处理器隔行分割,例如:
com.example.compiler.ComponentProcessor
com.example.compiler.MyProcessor
也可以通过auto-service自动生成相关配置文件
1. 在build.gradle中添加依赖
dependencies{
compileOnly 'com.google.auto.service:auto-service:1.0-rc7'
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7'
}
2.在注解处理器上添加@AutoService
@AutoService(Processor.class)
public class ComponentProcessor extends AbstractProcessor {
}
示例
在确定使用APT生成代码时,可以使用javapoet工具,并且需要指定要生成的java代码格式,生成的代码格式如下:
public final class MainActivity$$ARouter {
public static Class findTargetClass(String path) {
return path.equalsIgnoreCase("/app/MainActivity") ? MainActivity.class : null;
}
}
@AutoService(Processor.class)
@SupportedAnnotationTypes({"com.example.annotation.RouterTest"})
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class MyProcessor extends AbstractProcessor {
// 操作Element工具类 (类、函数、属性都是Element)
private Elements elementUtils;
// type(类信息)工具类,包含用于操作TypeMirror的工具方法
private Types typeUtils;
private Messager messager;
private Filer filer;
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
elementUtils = processingEnvironment.getElementUtils();
typeUtils = processingEnvironment.getTypeUtils();
messager = processingEnvironment.getMessager();
filer = processingEnvironment.getFiler();
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
if (set.isEmpty()) return false;
Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(RouterTest.class);
for (Element element : elements) {
parseElement(element);
}
return true;
}
/**
* 生成代码的示例,可以通过ARouter注解生成类,根据path获取对应的class对象
*
* @param element
*/
private void parseElement(Element element) {
String packageName = elementUtils.getPackageOf(element).getQualifiedName().toString();
String className = element.getSimpleName().toString();
messager.printMessage(Diagnostic.Kind.NOTE, "=MyProcessor=" + packageName + "/" + className);
RouterTest aRouter = element.getAnnotation(RouterTest.class);
MethodSpec fun = MethodSpec.methodBuilder("findTargetClass")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(Class.class)
.addParameter(String.class, "path")
.addStatement("return path.equalsIgnoreCase($S) ? $T.class : null",
aRouter.path(), ClassName.get((TypeElement) element))
.build();
TypeSpec clazz = TypeSpec.classBuilder(className + "$$ARouter")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(fun)
.build();
JavaFile javaFile = JavaFile.builder(packageName, clazz)
.build();
try {
javaFile.writeTo(filer);
} catch (IOException e) {
e.printStackTrace();
}
}
}
@RouterTest(path = "/app/MainActivity")
public class MainActivity extends AppCompatActivity {
}
Rebuild Project 后就会自动生成MainActivity$$ARouter类
本文地址:https://blog.csdn.net/qq_30359699/article/details/107661953
下一篇: Springboot定时任务