欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

自动生成代码工具--APT

程序员文章站 2022-04-12 22:10:07
APT(Annotation Processing Tool)注解处理器,是javac的一个工具,它用来在编译时扫描和处理注解(Annotation)。它可以生成Java代码,同时这些代码会跟手工白那些的Java的代码一样被Javac编译。虚处理器(javax.annotation.processing.AbstractProcessor) 每个处理器都继承自AbstractProcessor,相关Api如下:import java.util.Set;import javax......

       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包看起来如下:

自动生成代码工具--APT

打进.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

相关标签: 架构师