APT即Annotatino Processing Tool, 他的做用是处理代码中的注解, 用来生成代码, 换句话说, 这是用代码生成代码的工具, 减小boilerplate代码.html
咱们经过一个简单的例子来简单APT的工做过程, 由于本文demo不设计ide及gradle等, 请注意包名及import问题.java
根据上一篇博客Java中的自定义注解, 首先设计一个自定义注解MyAnnotation
.ide
package com.example; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.SOURCE) // 只保留到编译阶段 @Target(ElementType.TYPE) // 可用于类, 接口.. public @interface MyAnnotation { }
下面来看一下咱们的主角, Processor:工具
package com.example; 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; import java.util.HashSet; import java.util.Set; public class MyProcessor extends AbstractProcessor { // Processor初始化回调 @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); System.out.println("MyProcessor init"); } // processor处理过程的回调, 若是须要生成代码, 就在这个方法中写. 这个demo暂时不演示代码生成. @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { System.out.println("process"); return false; } @Override public Set<String> getSupportedAnnotationTypes() { // 在此处声明该processor支持的注解类型 Set<String> set = new HashSet<>(); set.add(MyAnnotation.class.getCanonicalName()); return set; } @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } }
那么咱们如何把这个apt注册给javac呢? 咱们将项目以常规的模式打包, 可是在META-INF目录中加入一个services
文件夹, 在其中建立一个名为javax.annotation.processing.Processor
的文件, 以文本将processor的完整名字写进去, 若是有多个processor, 换行便可.测试
javax.annotation.processing.Processor
的内容:gradle
com.example.MyProcessor
最终jar包的结构:设计
mp.jar // jar包名字随意起 com example MyProcess.class MyAnnotation.class META-INF services javax.annotation.processing.Processor MANIFEST.MF
测试的例子很简单:code
@MyAnnotation public class Sample { public static void main(String[] args) { System.out.printf("Hello, World!"); } }
咱们用javac
编译这个文件htm
$ javac -cp mp.jar Sample.java MyProcessor init process process
能够看到, 咱们的Process已经生成了, 可是process过程输出了两次, 缘由能够参考下图:blog
process
的过程会进行两边, 咱们代码生成的过程应该在第一遍, 由于第二次processor的过程应当负责作一些清理的工做, 某些打包工具可能不会编译在第二阶段生成的.java源文件.
if (!roundEnv.processingOver()) { ... }