目录
0x01 Lombok
Lombok是Java开源的工具类库,用于对Java源码的增强,提高开发者的开发效率,例如在POJO上添加@Getter和@Setter注解,源码经过编译后会自动生成私有属性的get和set方法,在Java的日常开发中基本属于必备的工具。这种实现是Java在前端编译时,基于给定的规则,动态生成语法树节点,并插入到对应的父节点上,这就是Javac提供的插入式注解处理器的能力
深入解析Java编译器:源码剖析与实例详解 - 第8章
Java在JDK 1.5版本中提供了对注解(Annotation)的支持,在JDK 1.6版本中又提供了插入式注解处理API(Pluggable Annotation Processing API),我们可以编写自定义的注解处理器并使用这些API来完成相应的功能
...
0x02 插入式注解处理器
插入式注解处理器的执行时机是在语法分析之后语义分析之前,抽象语法树生成处理的阶段,如下:
AbstractProcessor
自定义注解处理器需要继承AbstractProcessor类,需要覆写以下4个方法:
- init()方法:接收ProcessingEnvironment类型的参数可以初始化许多注解操作的工具类
- getSupportedOptions()方法:器配置支持的选项,如果不覆写这个方法,AbstractProcessor类中默认的实现会读取@SupportedOptions注解的配置;
- getSupportedAnnotationTypes()方法:配置支持的注解类型,如果不覆写这个方法,AbstractProcessor类中默认的实现会读取@SupportedAnnotationTypes注解的配置;
- getSupportedSourceVersion()方法:配置支持的JDK版本。如果不覆写这个方法,AbstractProcessor类中默认的实现会读取@SupportedSourceVersion注解的配置。
注解配置参数
- -XprintProcessorInfo命令:输出有关请求处理程序处理哪些注解的信息。
- -XprintRounds命令:输出有关注解处理循环的信息。
- -processor命令:使用类的全限定名指定具体的注解处理器类,如chapter8.GetSet Processor,因为类要通过loadClass()方法来加载,该方法要求加载的类必须是全限定名。可以指定多个处理器,多个处理器用逗号隔开。
- -processpath命令:指定搜索注解处理器的路径,如果没有指定此选项,默认在类路径classpath中搜索。
- -proc:命令:当命令为-proc:none时不对注解进行任何处理,仅编译Java源文件;当命令为-proc:only时仅运行注解处理器,不需要编译Java源文件。
- -Xprint命令:如果配置了这个命令,则会运行Javac本身提供的一个注解处理器类PrintingProcessor,这个类会打印当前正在编译的Java类的源代码。需要注意的是,指定这个命令会导致其他注解处理器类失效。
- -Akey=value:可以为正在执行的注解处理器提供一些客户端参数,不过需要在注解处理器上预先配置,可以通过注解@SupportedOptions或者覆写方法getSupported Options()来进行配置。
在JavacProcessingEnvironment类的构造方法中读取配置命令的值,然后通过成员变量进行保存
// 来源:com.sun.tools.javac.processing.JavacProcessingEnvironment
public final boolean printProcessorInfo;
public final boolean printRounds;
public final boolean procOnly;
public final Map<String, String> processorOptions;
在JavacProcessingEnvironment类的构造方法中初始化这些成员变量,代码如下
// 来源:com.sun.tools.javac.processing.JavacProcessingEnvironment
printProcessorInfo = options.isSet(XPRINTPROCESSORINFO);
printRounds = options.isSet(XPRINTROUNDS);
procOnly = options.isSet(PROC, "only") || options.isSet(XPRINT);
processorOptions = initProcessorOptions(context);
工具类
JavacProcessingEnvironment类定义了几个工具类相关的成员变量
// 来源:com.sun.tools.javac.processing.JavacProcessingEnvironment
private final JavacFiler filer;
private final JavacMessager messager;
private final JavacElements elementUtils;
private final JavacTypes typeUtils;
在JavacProcessingEnvironment类的构造方法中初始化这些成员变量
// 来源:com.sun.tools.javac.processing.JavacProcessingEnvironment
filer = new JavacFiler(context);
messager = new JavacMessager(context, this);
elementUtils = JavacElements.instance(context);
typeUtils = JavacTypes.instance(context);
介绍以上4个工具类:
-
JavacFiler类:用来创建新的Java源文件、Class文件及辅助文件。
-
Messager类:用来报告错误、警告或其他提示信息。
-
JavacElements类:实现了javax.lang.model.util.Elements接口,用于操作Element的工具方法。
- Symbol及相关的子类,它们都直接或间接实现了javax.lang.model.element包中定义的一些接口
-
JavacTypes类:实现了javax.lang.model.util.Types接口,用于操作TypeMirror的工具方法。
- TypeMirror可以将Type及相关的子类型映射为TypeMirror规定的一套接口,将Symbol及相关的子类型映射为Element规定的一套接口,这样就可以在注解处理器中访问Javac内部才能使用的Symbol与Type对象
0x03初始化注解处理器
Javac在词法分析(抽象语法树)时会初始化注解处理器
JavaCompiler
// 来源:src/com/sun/tools/javac/main/JavaCompiler.java
public void compile(List<JavaFileObject> sourceFileObjects,
List<String> classnames,
Iterable<? extends Processor> processors){
...
// 初始化注解处理器
initProcessAnnotations(processors);
...
}
// 初始化注解处理器
public void initProcessAnnotations(Iterable<? extends Processor> processors) {
...
// 初始化注解构造器
procEnvImpl = new JavacProcessingEnvironment(context, processors);
processAnnotations = procEnvImpl.atLeastOneProcessor();
...
}
JavacProcessingEnvironment
// 来源:src/com/sun/tools/javac/processing/JavacProcessingEnvironment.java
// 在JavacProcessingEnvironment类的构造方法中读取配置命令的值,然后通过成员变量进行保存
public JavacProcessingEnvironment(Context context, Iterable<? extends Processor> processors) {
...
// 初始化参数
printProcessorInfo = options.isSet(XPRINTPROCESSORINFO);
...
// processorOptions保存-Akey=value配置命令的值
processorOptions = initProcessorOptions(context);
...
messages = JavacMessages.instance(context);
// 初始化processorIterator变量
initProcessorIterator(context, processors);
}
private void initProcessorIterator(Context context, Iterable<? extends Processor> processors) {
....
// 首先获取-processor命令指定的注解处理器,
String processorNames = options.get(PROCESSOR);
// 拿到文件管理器
JavaFileManager fileManager = context.get(JavaFileManager.class);
try {
...
// 当配置了-processpath命令时,会在此路径下调用fileManager.getClassLoader()方法创建对应的类加载器,
// 否则在classpath路径下创建对应的类加载器。
// 如果获取到的值processorNames不为空,也就是配置了-processor命令
if (processorNames != null) {
// 那么创建一个NameProcessIterator迭代器对象
processorIterator = new NameProcessIterator(processorNames, processorClassLoader, log);
} else {
// 否则创建一个ServiceIterator迭代器对象
processorIterator = new ServiceIterator(processorClassLoader, log);
}
} catch (SecurityException e) {
...
}
}
// 初始化discoveredProcs变量
discoveredProcs = new DiscoveredProcessors(processorIterator);
}
JavacProcessingEnvironment#DiscoveredProcessors
// 来源:src/com/sun/tools/javac/processing/JavacProcessingEnvironment#DiscoveredProcessors
// DiscoveredProcessors类实现了Iterable<ProcessorState>接口,
// 使用迭代器类ProcessorStateIterator来迭代ProcessorState对象,
// 这个迭代器也是借助processorIterator来完成注解处理器迭代的
class DiscoveredProcessors implements Iterable<ProcessorState> {
// processorIterator保存了NameProcessIterator或ServiceIterator对象
Iterator<? extends Processor> processorIterator;
// procStateList保存了当前已经被封装为ProcessorState对象的所有注解处理器
ArrayList<ProcessorState> procStateList;
}
JavacProcessingEnvironment#ProcessorState
// 来源:src/com/sun/tools/javac/processing/JavacProcessingEnvironment#ProcessorState
static class ProcessorState {
// 保存的具体的注解处理器
public Processor processor;
// contributed表示此注解处理器是否运行过process()方法
// 如果运行过process()方法,则这个变量的值将被设置为true
public boolean contributed;
// 保存了注解处理器能够处理的注解类型
private ArrayList<Pattern> supportedAnnotationPatterns;
// 保存了注解处理器能够处理的注解选项
private ArrayList<String> supportedOptionNames;
ProcessorState(Processor p, Log log, Source source, ProcessingEnvironment env) {
processor = p;
contributed = false;
try {
// 处理注解处理器的初始化信息
processor.init(env);
// 处理注解处理器支持的Java源代码版本
checkSourceVersionCompatibility(source, log);
// 处理注解处理器支持处理的注解类型
supportedAnnotationPatterns = new ArrayList<Pattern>();
// 调用注解处理器的getSupportedAnnotationType()方法来获取支持处理的注解类型
// 并添加到supportedAnnotationPatterns集合中
for (String importString : processor.getSupportedAnnotationTypes()) {
supportedAnnotationPatterns.add(importStringToPattern(importString,
processor,
log));
}
// 处理注解处理器支持的注解选项
supportedOptionNames = new ArrayList<String>();
// 调用注解处理器的getSupportedOptions()方法来获取支持的注解选项
for (String optionName : processor.getSupportedOptions() ) {
if (checkOptionName(optionName, log))
supportedOptionNames.add(optionName);
}
} catch (Throwable t) {
throw new AnnotationProcessingError(t);
}
}
}
以上为注解处理器初始化关键代码
最终,注解处理器被封装为JavacProcessingEnvironment#ProcessorState
进行初始化
并存储在JavacProcessingEnvironment#DiscoveredProcessors
的迭代器中
为后续的运行做准备
0x04运行注解处理器
JavaCompiler
// 来源:src/com/sun/tools/javac/main/JavaCompiler.java
public void compile(List<JavaFileObject> sourceFileObjects,
List<String> classnames,
Iterable<? extends Processor> processors){
...
// 调用parseFiles()方法得到List<JCCompilationUnit>对象
// 调用enterTrees()方法完成符号的输入
delegateCompiler = processAnnotations(
// 不过在运行注解处理器之前还会调用enterTrees()方法,
// 这个方法会完成符号输入的第一与第二阶段,
// 同时也会对声明及定义的语法树节点进行标注,
// 因此才能在后续的注解处理器运行阶段操作TypeMirror与Element
enterTrees(stopIfError(CompileState.PARSE, parseFiles(sourceFileObjects))),
_);
...
}
public JavaCompiler processAnnotations(List<JCCompilationUnit> roots,_) {
...
// 在这之前会判断是否有必要调用JavacProcessingEnvironment类的doProcessing()方法运行注解处理器
// 调用方法后将返回一个新的JavaCompiler对象,
// 使用这个对象将继续执行Java源代码的编译,
// 所以说注解处理器能够影响Javac的编译过程
JavaCompiler c = procEnvImpl.doProcessing(context, roots, _, _);
...
return c;
}
JavacProcessingEnvironment.doProcessing
// 来源:src/com/sun/tools/javac/processing/JavacProcessingEnvironment
// 执行注解处理器处理
public JavaCompiler doProcessing(Context context,
List<JCCompilationUnit> roots,
List<ClassSymbol> classSymbols,
Iterable<? extends PackageSymbol> pckSymbols) {
...
// 出现错误退出标识
boolean errorStatus;
// 生成新文件标识
boolean moreToDo;
/*
如果注解处理器运行process()方法后产生了新的Java源文件,
Javac会重新运行一轮注解处理器,因此只要运行一轮注解处理器后有新的Java源文件产生后,
就会接着重新运行一轮注解处理器,直到没有新的文件产生
*/
do {
// 运行第一轮的注解处理器
// 调用Round对象的run()方法来执行注解处理的逻辑,
// Round对象代表了循环调用注解处理器处理语法树的过程
round.run(false, false);
// 当运行完这一轮注解处理器时,如果没有发现错误并且又有新的文件
// 生成时,需要进行下一轮注解处理器
errorStatus = round.unrecoverableError();
// 如果有新的文件产生,也就是当调用moreToDo()方法返回true时
// 需要调用当前Round对象的next()方法得到一个新的Round对象,
// 并将保存了新产生的文件的集合传递给新的Round对象
moreToDo = moreToDo();
round.showDiagnostics(errorStatus || showResolveErrors);
// 调用round.next()方法创建新的Round对象
// 每一次循环都会创建一个Round对象
round = round.next(
new LinkedHashSet<JavaFileObject>(filer.getGeneratedSourceFileObjects()),
new LinkedHashMap<String,JavaFileObject>(filer.getGeneratedClasses()));
...
} while (moreToDo && !errorStatus);
// 运行最后一轮注解处理器
round.run(true, errorStatus);
...
return compiler;
}
JavacProcessingEnvironment#Round
来源:com.sun.tools.javac.processing.JavacProcessingEnvironment.Round
// 创建一个新的Round
// 参数classSymbols列表一般为空
Round(Context context, List<JCCompilationUnit> roots, List<ClassSymbol> classSymbols) {
...
// 调用getTopLevelClasses()方法就是将roots列表中保存的所有编译单元下定义的顶层类追加到topLevelClasses列表中
topLevelClasses =
getTopLevelClasses(roots).prependList(classSymbols.reverse());
packageInfoFiles = getPackageInfoFiles(roots);
// 调用findAnnotationsPresent()方法查找在topLevelClasses列表的顶层类中使用到的注解类型
findAnnotationsPresent();
}
// 调用findAnnotationsPresent()方法查找在topLevelClasses列表的顶层类中使用到的注解类型
// 查找所有使用到的注解类型并保存到Round类的annotationsPresent中
void findAnnotationsPresent() {
// 通过ComputeAnnotationSet类对语法树进行扫描,找到使用到的注解类型
ComputeAnnotationSet annotationComputer = new ComputeAnnotationSet(elementUtils);
annotationsPresent = new LinkedHashSet<TypeElement>();
for (ClassSymbol classSym : topLevelClasses)
annotationComputer.scan(classSym, annotationsPresent);
for (PackageSymbol pkgSym : packageInfoFiles)
annotationComputer.scan(pkgSym, annotationsPresent);
}
// 运行注解处理器
void run(boolean lastRound, boolean errorStatus) {
...
try {
// 第一轮注解处理器的调用时,lastRound为false
// lastRound为true,标识最后一轮注解处理器
if (lastRound) {
filer.setLastRound(true);
Set<Element> emptyRootElements = Collections.emptySet(); // immutable
RoundEnvironment renv = new JavacRoundEnvironment(true,
errorStatus,
emptyRootElements,
JavacProcessingEnvironment.this);
discoveredProcs.iterator().runContributingProcs(renv);
} else {
// 第一轮时调用
discoverAndRunProcs(context, annotationsPresent, topLevelClasses, packageInfoFiles);
}
}
...
}
JavacProcessingEnvironment#ComputeAnnotationSet
public static class ComputeAnnotationSet extends
ElementScanner7<Set<TypeElement>, Set<TypeElement>> {
final Elements elements;
public ComputeAnnotationSet(Elements elements) {
super();
this.elements = elements;
}
@Override
public Set<TypeElement> visitPackage(PackageElement e, Set<TypeElement> p) {
// Don't scan enclosed elements of a package
return p;
}
@Override
// 在这个方法中查找所有已被使用的注解类型
public Set<TypeElement> scan(Element e, Set<TypeElement> p) {
// 如果找到,就将注解类型对应的Element对象存到p集合中,
// 也就是保存到了Round类中定义的类型为Set<TypeElement>的annotationsPresent集合。
for (AnnotationMirror annotationMirror :
elements.getAllAnnotationMirrors(e) ) {
Element e2 = annotationMirror.getAnnotationType().asElement();
// 将需要处理的注解类型放入Set中
p.add((TypeElement) e2);
}
return super.scan(e, p);
}
}
JavacProcessingEnvironment#DiscoveredProcessors
// 来源:src/com/sun/tools/javac/processing/JavacProcessingEnvironment#DiscoveredProcessors
// 运行注解处理器
private void discoverAndRunProcs(Context context,
Set<TypeElement> annotationsPresent,
List<ClassSymbol> topLevelClasses,
List<PackageSymbol> packageInfoFiles) {
// 需要处理的元素的全限定名和元素的映射
Map<String, TypeElement> unmatchedAnnotations =
new HashMap<String, TypeElement>(annotationsPresent.size());
// 建立全限定名到对应TypeElement对象的映射关系
for(TypeElement a : annotationsPresent) {
unmatchedAnnotations.put(a.getQualifiedName().toString(),
a);
}
// 让处理"*"的注解处理器也有机会运行
if (unmatchedAnnotations.size() == 0)
unmatchedAnnotations.put("", null);
// 可通过迭代器获取所有的注解处理器
DiscoveredProcessors.ProcessorStateIterator psi = discoveredProcs.iterator();
Set<Element> rootElements = new LinkedHashSet<Element>();
rootElements.addAll(topLevelClasses);
rootElements.addAll(packageInfoFiles);
rootElements = Collections.unmodifiableSet(rootElements);
// 准备这一轮Round运行的环境
// renv就是在调用注解处理器的process()方法时传递的第2个RoundEnvironment类型的参数
// renv会保存上一轮Round运行后的一些状态,可以在覆写process()方法时调用相关方法获取这些信息进行逻辑处理
RoundEnvironment renv = new JavacRoundEnvironment(false,
false,
rootElements,
JavacProcessingEnvironment.this);
// 当有待处理的注解并且有注解处理器的情况下,查找能处理注解的注解处理器并运行
while(unmatchedAnnotations.size() > 0 && psi.hasNext() ) {
// 调用psi.next()方法获取ProcessorState对象
ProcessorState ps = psi.next();
// 匹配出可以被处理的注解名
Set<String> matchedNames = new HashSet<String>();
// 匹配出可以被处理的元素
Set<TypeElement> typeElements = new LinkedHashSet<TypeElement>();
// 查找注解处理器能够处理的注解并存储到matchedNames集合中
// 当unmatchedAnnotations集合中存在注解类型并且也能查找到注解处理器时,查找能处理这些注解类型的注解处理器并运行
for (Map.Entry<String, TypeElement> entry: unmatchedAnnotations.entrySet()) {
String unmatchedAnnotationName = entry.getKey();
// 从unmatchedAnnotations集合中查找是否含有能被当前的注解处理器ps处理的注解类型
if (ps.annotationSupported(unmatchedAnnotationName) ) {
// 添加匹配出可以被处理的注解
matchedNames.add(unmatchedAnnotationName);
TypeElement te = entry.getValue();
if (te != null)
// 添加匹配出可以被处理的元素
// TypeElement对象就是注解处理器覆写process()方法时接收的
// 第一个Set<? extends TypeElement>类型的参数,表示此注解处理器处理的注解类型
typeElements.add(te);
}
}
// 当注解处理器ps能够处理某些注解或者在之前的Round中运行过此注解处理器时
if (matchedNames.size() > 0 || ps.contributed) {
// 调用callProcessor()方法运行此注解处理器
boolean processingResult = callProcessor(ps.processor, typeElements, renv);
ps.contributed = true;
ps.removeSupportedOptions(unmatchedProcessorOptions);
if (printProcessorInfo || verbose) {
log.printNoteLines("x.print.processor.info",
ps.processor.getClass().getName(),
matchedNames.toString(),
processingResult);
}
// 注解处理器执行成功,移除处理器名称
if (processingResult) {
unmatchedAnnotations.keySet().removeAll(matchedNames);
}
}
}
unmatchedAnnotations.remove("");
...
// 再次运行之前Round中运行过的注解处理器
psi.runContributingProcs(renv);
...
}
// 运行在procStateList中剩下的还没有运行过的注解处理器
public void runContributingProcs(RoundEnvironment re) {
if (!onProcInterator) {
Set<TypeElement> emptyTypeElements = Collections.emptySet();
while(innerIter.hasNext()) {
ProcessorState ps = innerIter.next();
if (ps.contributed)
callProcessor(ps.processor, emptyTypeElements, re);
}
}
}
以上为运行注解处理器的关键代码,大致流程为:
JavaCompiler.processAnnotations()
处理注解JavacProcessingEnvironment.doProcessing()
执行处理JavacProcessingEnvironment#Round
多轮调用执行,因为存在编译过程中生成新的文件JavacProcessingEnvironment#ComputeAnnotationSet
查找所有被处理注解打标的文件JavacProcessingEnvironment#Round.run()
执行注解处理器处理DiscoveredProcessors.discoverAndRunProcs()
运行注解处理器DiscoveredProcessors.runContributingProcs()
运行在procStateList中剩下的还没有运行过的注解处理器
0x05 自己实现@getter
自定义注解处理器类
package book.chapter8;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.*;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.util.Set;
/**
* 自定义get处理器
*/
@SupportedAnnotationTypes({ "book.chapter8.Getter" })// 注解类全路径
@SupportedSourceVersion(SourceVersion.RELEASE_7) // 支持的jdk版本
public class GetSetProcessor extends AbstractProcessor {
// 用来报告错误、警告或其他提示信息
private Messager messager;
// java语法树上下文
private JavacTrees trees;
// Java语法树构造器
private TreeMaker treeMaker;
// 可以用来创建新的符号
private Names names;
// 初始化,准备环境和工具类
@Override
public synchronized void init(ProcessingEnvironment pe) {
super.init(pe);
messager = pe.getMessager();
// 初始化一颗树
this.trees = JavacTrees.instance(processingEnv);
// 拿到当前环境的上下文
Context context = ((JavacProcessingEnvironment) pe).getContext();
// 初始化一个语法树构造器
this.treeMaker = TreeMaker.instance(context);
// 初始化一个符号构造
this.names = Names.instance(context);
}
// 处理
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment re) {
// 获取getter注解关联的类
Set<? extends Element> elems = re.getElementsAnnotatedWith(Getter.class);
// new一个树翻译器
TreeTranslator tt = new TreeTranslator() {
@Override
public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {
List<JCTree.JCVariableDecl> jcVariableDeclList = List.nil();
// 将类中定义的成员变量保存到jcVariableDeclList列表中
for (JCTree tree : jcClassDecl.defs) {
if (tree.getKind().equals(Tree.Kind.VARIABLE)) {
JCTree.JCVariableDecl jcVariableDecl = (JCTree.JCVariableDecl) tree;
jcVariableDeclList = jcVariableDeclList.append(jcVariableDecl);
}
}
// 处理每一个成员变量
for (JCTree.JCVariableDecl jcVariableDecl : jcVariableDeclList) {
messager.printMessage(Diagnostic.Kind.NOTE, jcVariableDecl.getName() + " has been processed");
// 调用makeGetterMethodDecl()方法为成员变量创建getXxx()方法
// 对应的语法树并追加到jcClassDecl.defs中
jcClassDecl.defs = jcClassDecl.defs.prepend(makeGetterMethodDecl(jcVariableDecl));
}
super.visitClassDef(jcClassDecl);
}
};
// 将上面的翻译器放到每个元素中
for (Element element : elems) {
JCTree jcTree = trees.getTree(element);
jcTree.accept(tt);
}
return true;
}
// 为成员变量创建getXxx()方法对应的语法树
private JCTree.JCMethodDecl makeGetterMethodDecl(JCTree.JCVariableDecl jcVariableDecl) {
// 描述列表
ListBuffer<JCTree.JCStatement> statements = new ListBuffer<>();
// this关键字描述
JCTree.JCIdent jci = treeMaker.Ident(names.fromString("this"));
// 变量描述,放入this关键字
JCTree.JCFieldAccess jcf = treeMaker.Select(jci, jcVariableDecl.getName());
// return 描述,放入变量描述
JCTree.JCReturn jcr = treeMaker.Return(jcf);
// 放入到描述列表
statements.append(jcr);
// 方法体位空
JCTree.JCBlock body = treeMaker.Block(0, statements.toList());
// 方法定义
return treeMaker.MethodDef(
// 访问等级
treeMaker.Modifiers(Flags.PUBLIC),
// 方法名
getNewMethodName(jcVariableDecl.getName()),
// 返回值类型
jcVariableDecl.vartype,
// 参数类型列表为空
List.<JCTree.JCTypeParameter>nil(),
// 参数描述列表为空
List.<JCTree.JCVariableDecl>nil(),
// 参数表达式为空(比如...)
List.<JCTree.JCExpression>nil(),
// 方法体
body,
null);
}
// 获取getXxx的方法名
private Name getNewMethodName(Name name) {
String s = name.toString();
String mn = "get" + s.substring(0, 1).toUpperCase() + s.substring(1,name.length());
return names.fromString(mn);
}
}
自定义的注解类
package book.chapter8;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface Getter { }
写一个类测试
package book.chapter8;
@Getter
public class TestAnnotation {
private String name;
private int age;
}
测试
package book.chapter8;
import javax.tools.ToolProvider;
public class Test{
public static void main(String[] args) {
javax.tools.JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int results = compiler.run(null, null, null, new String[]{
// -processor命令指定具体的注解处理器类
"-processor","book.chapter8.GetSetProcessor",
// -processorpath命令指定搜索注解处理器的路径
"-processorpath","/Users/yangluchao/Documents/GitHub/javac_study/src/book/chapter8",
// 运行后会根据/Users/yangluchao/Documents/GitHub/javac_study/src/book/chapter8/TestAnnotation.java
// 在“/Users/yangluchao/Documents/GitHub/javac_study/save/ylcComplieTest”路径下
// 生成TestAnnotation.class类
"-d","/Users/yangluchao/Documents/GitHub/javac_study/save/ylcComplieTest",
"/Users/yangluchao/Documents/GitHub/javac_study/src/book/chapter8/TestAnnotation.java",
});
}
}
执行结果
0x06 总结
有了插入式注解处理器让Java的开发更加灵活,在性能监控、安全扫描、业务插桩等方面可以有比较深入的应用。在日常开发中也更加便利(比如lombok)
标签:javac,new,插入式,JavacProcessingEnvironment,注解,public,处理器 From: https://www.cnblogs.com/ylc0x01/p/17331634.html