Java中的屠龙之术
JCTree的介绍
CTree(Java Compiler Tree API)是 Java 编译器提供的一组 API,用于操作和分析 Java 代码的抽象语法树(AST)。JCTree API 在
com.sun.tools.javac.tree
包中提供,并且是 Java 编译器的一部分。它允许开发者在编译期间访问和修改 Java 代码的结构,从而实现代码生成、代码检查、代码转换等功能。JCTree API 允许你以编程方式操作 AST 中的不同元素,如类、方法、字段、表达式等
以下是一些常见的 JCTree API 类和接口,以及它们的一些重要方法:
- JCCompilationUnit:表示整个编译单元(源文件)的抽象语法树。它是 AST 的根节点。
- JCClassDecl:表示类或接口的声明。
- JCMethodDecl:表示方法的声明。
- JCVariableDecl:表示变量(字段)的声明。
- JCExpression:表示表达式,如赋值、算术运算、方法调用等。
- JCAssign:赋值语句语法树节点
- JCIdent:标识符语法树节点,可以是变量,类型,关键字等等
- JCStatement:表示语句,如 if、while、for、return 等。
- JCBlock:语句块语法树节点
- JCReturn:return语句语法树节点
- JCTreeVisitor<R, D>:用于遍历和访问 AST 的访问者接口。你可以通过实现这个接口来定义如何处理不同类型的节点。
JavacTrees
com.sun.tools.javac.api.JavacTrees
是 Java 编译器(javac
)提供的一个工具类,用于在注解处理器中访问和操作抽象语法树(AST)。它为注解处理器提供了一些便捷的方法,使得开发者可以更容易地在编译时处理 Java 源代码的结构。
JavacTrees
类主要用于获取与 AST 相关的一些工具和对象,包括:
TreeMaker
:用于创建新的 AST 节点,如创建类、方法、字段、表达式等。
Element
和TypeElement
的转换:可以将Element
对象(表示程序元素)转换为对应的TypeElement
、ExecutableElement
等对象,以便进行更详细的操作。
getTree(Element element)
:获取给定程序元素的对应 AST 节点。通过调用这个方法,你可以获取到表示该元素的 AST 节点。
getScope(Element element)
:获取给定程序元素的对应作用域对象。这个作用域对象可以用于查询和分析元素的可见性等信息。请注意,
com.sun.tools.javac.api.JavacTrees
类属于com.sun.tools.javac
包,这意味着它位于javac
编译器的内部实现中。以下是一个简单的示例,演示了如何在注解处理器中使用
JavacTrees
获取 AST 相关的信息:
TreeMaker
TreeMaker.Modifiers
TreeMaker.Modifiers
方法用于创建访问标志语法树节点(JCModifiers)public JCModifiers Modifiers(long flags) { return Modifiers(flags, List.< JCAnnotation >nil()); } public JCModifiers Modifiers(long flags, List<JCAnnotation> annotations) { JCModifiers tree = new JCModifiers(flags, annotations); boolean noFlags = (flags & (Flags.ModifierFlags | Flags.ANNOTATION)) == 0; tree.pos = (noFlags && annotations.isEmpty()) ? Position.NOPOS : pos; return tree; }
- flags:访问标志
- annotations:注解列表
treeMaker.Modifiers(Flags.PUBLIC + Flags.STATIC + Flags.FINAL); public static final
TreeMaker.ClassDef
TreeMaker.ClassDef用于创建类定义语法树节点(JCClassDecl)
public JCClassDecl ClassDef(JCModifiers mods, Name name, List<JCTypeParameter> typarams, JCExpression extending, List<JCExpression> implementing, List<JCTree> defs) { JCClassDecl tree = new JCClassDecl(mods, name, typarams, extending, implementing, defs, null); tree.pos = pos; return tree; }
- mods:访问标志,可以通过
TreeMaker.Modifiers
来创建- name:类名
- typarams:泛型参数列表
- extending:父类
- implementing:实现的接口
- defs:类定义的详细语句,包括字段、方法的定义等等
TreeMaker.MethodDef
TreeMaker.MethodDef用于创建方法定义语法树节点(JCMethodDecl)
public JCMethodDecl MethodDef(JCModifiers mods, Name name, JCExpression restype, List<JCTypeParameter> typarams, List<JCVariableDecl> params, List<JCExpression> thrown, JCBlock body, JCExpression defaultValue) { JCMethodDecl tree = new JCMethodDecl(mods, name, restype, typarams, params, thrown, body, defaultValue, null); tree.pos = pos; return tree; } public JCMethodDecl MethodDef(MethodSymbol m, Type mtype, JCBlock body) { return (JCMethodDecl) new JCMethodDecl( Modifiers(m.flags(), Annotations(m.getAnnotationMirrors())), m.name, Type(mtype.getReturnType()), TypeParams(mtype.getTypeArguments()), Params(mtype.getParameterTypes(), m), Types(mtype.getThrownTypes()), body, null, m).setPos(pos).setType(mtype); }
- mods:访问标志
- name:方法名
- restype:返回类型
- typarams:泛型参数列表
- params:参数列表
- thrown:异常声明列表
- body:方法体
- defaultValue:默认方法(可能是interface中的哪个default)
- m:方法符号
- mtype:方法类型。包含多种类型,泛型参数类型、方法参数类型、异常参数类型、返回参数类型。
TreeMaker.VarDef
TreeMaker.VarDef用于创建字段/变量定义语法树节点
public JCVariableDecl VarDef(JCModifiers mods, Name name, JCExpression vartype, JCExpression init) { JCVariableDecl tree = new JCVariableDecl(mods, name, vartype, init, null); tree.pos = pos; return tree; } public JCVariableDecl VarDef(VarSymbol v, JCExpression init) { return (JCVariableDecl) new JCVariableDecl( Modifiers(v.flags(), Annotations(v.getAnnotationMirrors())), v.name, Type(v.type), init, v).setPos(pos).setType(v.type); }
- mods:访问标志
- name:参数名称
- vartype:类型
- init:初始化语句
- v:变量符号
TreeMaker.Ident
TreeMaker.Ident用于创建标识符语法树节点
public static class JCIdent extends JCTree.JCExpression implements IdentifierTree { public Name name;//标识符的名字 public Symbol sym;//代表类时为包名+类名,代表其他类型数据时为null protected JCIdent(Name var1, Symbol var2) { this.name = var1; this.sym = var2; } } -->创建实例: 获取变量textView的引用 treeMaker.Ident(names.fromString("textView"))))
TreeMaker.Return
TreeMaker.Return用于创建return语句
public static class JCReturn extends JCTree.JCStatement implements ReturnTree { public JCTree.JCExpression expr;//返回语句的结果字段 } -->例子:retrun this.xxx treeMaker.Return(treeMaker.Select( treeMaker.Ident(names.fromString("this")),names.fromString("xxx")));
TreeMaker.Select
TreeMaker.Select用于创建域访问/方法访问
public JCFieldAccess Select(JCExpression selected, Name selector) { JCFieldAccess tree = new JCFieldAccess(selected, selector, null); tree.pos = pos; return tree; } public JCExpression Select(JCExpression base, Symbol sym) { return new JCFieldAccess(base, sym.name, sym).setPos(pos).setType(sym.type); }
- selected:
.
运算符左边的表达式- selector:
.
运算符右边的表达式TreeMaker.Select(treeMaker.Ident(names.fromString("this")), names.fromString("name")); this.name
TreeMaker.Apply
TreeMaker.Apply用于创建方法调用语法树节点
public JCMethodInvocation Apply(List<JCExpression> typeargs, JCExpression fn, List<JCExpression> args) { JCMethodInvocation tree = new JCMethodInvocation(typeargs, fn, args); tree.pos = pos; return tree; }
- typeargs:参数类型列表
- fn:调用语句
- args:参数列表
TreeMaker.Assign
TreeMaker.Assign用户创建赋值语句语法树节点
ublic JCAssign Assign(JCExpression lhs, JCExpression rhs) { JCAssign tree = new JCAssign(lhs, rhs); tree.pos = pos; return tree; }
- lhs:赋值语句左边表达式
- rhs:赋值语句右边表达式
TreeMaker.Exec
TreeMaker.Exec用于创建可执行语句语法树节点
public JCExpressionStatement Exec(JCExpression expr) { JCExpressionStatement tree = new JCExpressionStatement(expr); tree.pos = pos; return tree; }
TreeMaker.Apply以及TreeMaker.Assign就需要外面包一层TreeMaker.Exec来获得一个JCExpressionStatement
TreeMaker.Block
TreeMaker.Block用于创建组合语句的语法树节点
public JCBlock Block(long flags, List<JCStatement> stats) { JCBlock tree = new JCBlock(flags, stats); tree.pos = pos; return tree; }
- flags:访问标志
- stats:语句列表
public static class JCBlock extends JCTree.JCStatement implements BlockTree { public long flags;//访问修复符 public List<JCTree.JCStatement> stats;//多行代码列表 } -->使用例子: List<JCTree.JCStatement> jcStatementList = List.nil(); treeMaker.Block(0, jcStatementList);//构建代码块
JCIf
if代码块; if(condition) {thenpart} else {elsepart}
public static class JCIf extends JCTree.JCStatement implements IfTree { public JCTree.JCExpression cond;//条件语句 public JCTree.JCStatement thenpart;//if的操作语句 public JCTree.JCStatement elsepart;//else的操作语句 }
JCForLoop
for循环代码块;for (init; cond; step) {body}
public static class JCForLoop extends JCTree.JCStatement implements ForLoopTree { public List<JCTree.JCStatement> init; public JCTree.JCExpression cond; public List<JCTree.JCExpressionStatement> step; public JCTree.JCStatement body; }
JCTry、JCCatch
public static class JCTry extends JCTree.JCStatement implements TryTree { public JCTree.JCBlock body;//try代码块 public List<JCTree.JCCatch> catchers;//JCCatch public JCTree.JCBlock finalizer;//final代码块 public List<JCTree> resources;//List.nil(),用不上的字段 public boolean finallyCanCompleteNormally;// } -->JCCatch public static class JCCatch extends JCTree implements CatchTree { public JCTree.JCVariableDecl param;//catch的异常类型 public JCTree.JCBlock body;//catch代码块 }
AbstractProcessor
AbstractProcessor
是 Java 注解处理器的一个抽象类,它是 Java 编译器提供的工具,用于处理源代码中的注解。注解处理器可以在编译时扫描和处理源代码中的注解信息,并根据注解生成代码、进行静态分析、执行代码检查等操作。注解处理器是 Java 编译器的一部分,它可以用于生成额外的代码,修改现有的代码结构,或者在编译期间执行其他任务。这使得注解处理器非常适用于一些元编程和自动化的场景。
AbstractProcessor
作为注解处理器的抽象类,提供了一些常用的方法和操作,使得开发者可以更方便地编写自定义的注解处理器。它是 Java 标准库中的一部分,位于javax.annotation.processing
包中。以下是
AbstractProcessor
类的一些重要方法和用途:
init
方法:在注解处理器被初始化时调用。开发者可以在这里进行初始化操作。
getSupportedAnnotationTypes
方法:返回一个字符串集合,表示该处理器支持处理哪些注解。这些注解可以是完全限定名,也可以使用通配符。
getSupportedSourceVersion
方法:返回一个表示支持的 Java 源代码版本的枚举值。通常返回SourceVersion.latestSupported()
。
process
方法:核心方法,用于处理注解。在这个方法中,你可以获取到编译器提供的注解信息和相关元素,然后执行处理逻辑。
ProcessingEnvironment
javax.annotation.processing.ProcessingEnvironment
是 Java 注解处理器的一个核心接口,它提供了注解处理器在编译时与编译环境进行交互的能力。通过ProcessingEnvironment
,注解处理器可以访问编译器提供的各种工具和信息,从而实现自定义的代码生成、静态分析、代码检查等功能。
ProcessingEnvironment
接口定义了许多有用的方法,使得注解处理器能够获取有关编译环境的各种信息。以下是一些ProcessingEnvironment
接口中常用的方法:
Messager getMessager()
:获取用于输出消息的Messager
对象,允许注解处理器在编译时输出信息、警告和错误。
Filer getFiler()
:获取用于生成文件的Filer
对象,允许注解处理器生成新的源代码文件、类文件等。
Elements getElementUtils()
:获取用于访问程序元素的Elements
对象,允许注解处理器访问和操作源代码中的各种元素。
Types getTypeUtils()
:获取用于处理类型信息的Types
对象,允许注解处理器执行类型检查、类型转换等操作。
Map<String, String> getOptions()
:获取注解处理器的选项集合,允许注解处理器获取外部传递的参数和选项。
Locale getLocale()
:获取当前环境的语言设置,可以用于在不同语言环境下生成本地化的消息。
RoundEnvironment
在 Java 注解处理器中,
RoundEnvironment
是一个用于表示当前编译轮次的对象,它提供了有关编译期间的注解信息和元素的访问接口。注解处理器在每个编译轮次都会被调用一次,并且每轮的RoundEnvironment
对象都会提供当前轮次中的注解和元素信息。每一轮的
RoundEnvironment
对象会包含一组元素,这些元素是被处理器所关注的注解所标注的程序元素(例如类、方法、字段等)。通过RoundEnvironment
,注解处理器可以获取到在当前轮次中被标注的元素,并进行相应的处理。下面是一些常见的
RoundEnvironment
方法和用途:
getElementsAnnotatedWith(Class<? extends Annotation> a)
:返回一个被给定注解标注的元素集合。通过传递注解的类对象,可以获取到被标注的类、方法、字段等元素。
getElementsAnnotatedWith(TypeElement a)
:与上述方法类似,但是接受一个TypeElement
参数。
getElementsAnnotatedWith(javax.lang.model.element.ElementKind kind)
:返回指定元素类型的元素集合,例如ElementKind.CLASS
、ElementKind.METHOD
等。
getRootElements()
:返回当前轮次中所有被处理的根元素,通常是源文件中的类。
ElementKind
javax.lang.model.element.ElementKind
是 Java 注解处理器中的一个枚举类型,用于表示程序元素(element)的种类或类型。程序元素是源代码中的各种构造,如类、接口、方法、字段等。ElementKind
枚举为每种元素提供了一个常量,帮助注解处理器在处理过程中判断和识别不同类型的元素。以下是
ElementKind
中的一些常见元素种类和对应的常量:
PACKAGE
:表示包(package)元素。
ENUM
:表示枚举类型(enum)元素。
CLASS
:表示类(class)元素。
INTERFACE
:表示接口(interface)元素。
ANNOTATION_TYPE
:表示注解类型(annotation type)元素。
ENUM_CONSTANT
:表示枚举常量(enum constant)元素。
FIELD
:表示字段(field)元素。
PARAMETER
:表示方法或构造函数的参数(parameter)元素。
LOCAL_VARIABLE
:表示局部变量(local variable)元素。
EXCEPTION_PARAMETER
:表示异常参数(exception parameter)元素。
METHOD
:表示方法(method)元素。
CONSTRUCTOR
:表示构造函数(constructor)元素。
STATIC_INIT
:表示静态初始化块(static initializer)元素。
INSTANCE_INIT
:表示实例初始化块(instance initializer)元素。
OTHER
:表示其他未知类型的元素。通过使用
ElementKind
,注解处理器可以在处理不同类型的元素时执行不同的逻辑。例如,你可以根据元素的种类来判断是否生成额外的代码,或者是否进行特定类型的静态分析。以下是一个简单的示例,演示如何使用
ElementKind
判断不同类型的元素:import javax.annotation.processing.*; import javax.lang.model.element.*; import javax.lang.model.SourceVersion; import java.util.Set; @SupportedAnnotationTypes("*") @SupportedSourceVersion(SourceVersion.RELEASE_8) public class ElementKindExample extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { for (Element element : roundEnv.getRootElements()) { ElementKind kind = element.getKind(); System.out.println("Element: " + element.getSimpleName() + ", Kind: " + kind); if (kind == ElementKind.CLASS) { System.out.println("Found class: " + element.getSimpleName()); } else if (kind == ElementKind.METHOD) { System.out.println("Found method: " + element.getSimpleName()); } else if (kind == ElementKind.FIELD) { System.out.println("Found field: " + element.getSimpleName()); } } return true; } }
在上述示例中,
ElementKindExample
注解处理器遍历所有根元素,并根据元素的种类输出相应的信息。这有助于你了解不同类型的元素在注解处理器中的表现和处理方式。通过熟悉和使用
ElementKind
,你可以更好地理解和操作程序元素,从而在注解处理器中实现各种功能。
ExecutableElement
javax.lang.model.element.ExecutableElement
是 Java 注解处理器中的一个接口,它表示可执行元素,即方法和构造函数。ExecutableElement
继承自Element
接口,提供了访问和操作方法和构造函数的属性和信息的方法。在注解处理器中,你可以使用
ExecutableElement
来获取方法和构造函数的相关信息,例如方法名、参数、返回类型、注解等。以下是
ExecutableElement
接口中的一些常用方法:
List<? extends VariableElement> getParameters()
:获取方法或构造函数的参数列表。
TypeMirror getReturnType()
:获取方法的返回类型。
List<? extends TypeMirror> getThrownTypes()
:获取方法可能抛出的异常类型列表。
TypeElement getEnclosingElement()
:获取包含该方法或构造函数的元素,通常是类或接口。
boolean isVarArgs()
:检查方法是否为可变参数方法。
boolean isDefault()
:检查方法是否为接口的默认方法。
List<? extends TypeParameterElement> getTypeParameters()
:获取方法或构造函数的类型参数列表。
List<? extends TypeMirror> getThrownTypes()
:获取方法可能抛出的异常类型列表。
ExecutableType asType()
:将此ExecutableElement
转换为ExecutableType
,用于进行类型检查。
TypeElement
javax.lang.model.element.TypeElement
是 Java 注解处理器中的一个接口,它表示程序元素中的类或接口。TypeElement
继承自Element
接口,提供了访问和操作类和接口的属性和信息的方法。在注解处理器中,你可以使用
TypeElement
来获取类和接口的相关信息,例如类名、父类、实现的接口、内部类、注解等。以下是
TypeElement
接口中的一些常用方法:
Name getQualifiedName()
:获取类或接口的限定名,以Name
对象表示。
TypeMirror getSuperclass()
:获取类的父类的类型。
List<? extends TypeMirror> getInterfaces()
:获取类或接口实现的接口的类型列表。
List<? extends Element> getEnclosedElements()
:获取类或接口中的成员元素,如字段、方法、内部类等。
TypeMirror asType()
:将此TypeElement
转换为DeclaredType
,用于进行类型检查。
boolean isInterface()
:检查是否为接口。
boolean isEnum()
:检查是否为枚举类型。
boolean isAnnotation()
:检查是否为注解类型。
boolean isClass()
:检查是否为类类型。
Messager
javax.annotation.processing.Messager
是 Java 注解处理器中的一个接口,它提供了向注解处理器的使用者(通常是开发者)报告消息、警告和错误的能力。通过Messager
,注解处理器可以向编译器输出信息,帮助开发者了解代码处理过程中的情况,以及可能需要修复的问题。
Messager
接口定义了一些方法,允许注解处理器输出消息、警告和错误。以下是Messager
接口中常用的方法:
void printMessage(Diagnostic.Kind kind, CharSequence msg)
:输出一条消息,可以是信息、警告或错误。
void printMessage(Diagnostic.Kind kind, CharSequence msg, Element e)
:输出一条消息,并指定与该消息关联的元素。
void printMessage(Diagnostic.Kind kind, CharSequence msg, Element e, AnnotationMirror a)
:输出一条消息,并指定与该消息关联的元素和注解镜像。
void printMessage(Diagnostic.Kind kind, CharSequence msg, Element e, AnnotationMirror a, AnnotationValue v)
:输出一条消息,并指定与该消息关联的元素、注解镜像和注解值。
void printMessage(Diagnostic.Kind kind, CharSequence msg, Element e, AnnotationMirror a, AnnotationValue v, AnnotationValue v1)
:输出一条消息,并指定与该消息关联的元素、注解镜像、注解值等。
void printMessage(Diagnostic.Kind kind, CharSequence msg, Element e, AnnotationMirror a, AnnotationValue v, AnnotationValue v1, AnnotationValue v2)
:输出一条消息,并指定与该消息关联的元素、注解镜像、注解值等。在编写注解处理器时,通常会使用
Messager
输出信息、警告和错误,以便在编译时向开发者传达处理结果和可能的问题。下面是一个简单的示例,展示了如何在注解处理器中使用Messager
输出消息和警告:
作用到类上捕获异常
package com.jct.demo.processor;
/**
* <b><code>CatchAndLogProcessor</code></b>
* <p/>
* Description
* <p/>
* <b>Creation Time:</b> 2023/8/14.
*
* @author zhennan.Xu
* @since terry-boot
*/
import com.sun.source.util.Trees;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.model.JavacElements;
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.util.Context;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Names;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.util.Set;
@SupportedAnnotationTypes("com.jct.demo.processor.CatchAndLog")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class CatchAndLogProcessor extends AbstractProcessor {
private Trees trees;
protected Messager messager;
// 封装了创建AST节点的一些方法
protected TreeMaker treeMaker;
// 提供了创建标识符的方法
protected Names names;
/**
* 用来处理Element的工具类
* Elements接口的对象,用于操作元素的工具类。
*/
private JavacElements elementUtils;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
trees = Trees.instance(processingEnv);
this.trees = JavacTrees.instance(processingEnv);
Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
this.treeMaker = TreeMaker.instance(context);
this.names = Names.instance(context);
messager = processingEnv.getMessager();
elementUtils = (JavacElements) processingEnv.getElementUtils();
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
System.out.println("进入process");
messager.printMessage(Diagnostic.Kind.NOTE, "TakeTimeProcessor注解处理器处理中");
TypeElement currentAnnotation = null;
// 遍历注解集合,也即@SupportedAnnotationTypes中标注的类型
for (TypeElement annotation : annotations) {
messager.printMessage(Diagnostic.Kind.NOTE, "遍历本注解处理器处理的所有注解,当前遍历到的注解是:" + annotation.getSimpleName());
currentAnnotation = annotation;
}
Set<? extends Element> elementSet = roundEnv.getElementsAnnotatedWith(CatchAndLog.class);
messager.printMessage(Diagnostic.Kind.NOTE, "CatchAndLogProcessor注解处理器处理@CatchAndLog注解");
for (Element element : elementSet) {
if (element.getKind() == ElementKind.METHOD) {
JCTree tree = (JCTree) trees.getTree(element);
System.out.println("进入循环");
if (tree instanceof JCTree.JCMethodDecl) {
JCTree.JCMethodDecl methodDecl = (JCTree.JCMethodDecl) tree;
// 方法名称
String methodName = element.getSimpleName().toString();
// 类的全限定名称
String className = element.getEnclosingElement().toString();
messager.printMessage(Diagnostic.Kind.NOTE, "当前被标注注解的方法所在的类是:" + className);
messager.printMessage(Diagnostic.Kind.NOTE, currentAnnotation.getSimpleName().toString() + "当前被标注注解的方法是:" + methodName);
enhanceMethodDecl(methodDecl);
}
}
}
return true;
}
private void enhanceMethodDecl(JCTree.JCMethodDecl methodDecl) {
//try {
//
//}catch (Exception ex) {
// ex.printStackTrace();
//}
JCTree.JCBlock tryBlock = methodDecl.body;
JCTree.JCVariableDecl exVar = createVarDef(treeMaker.Modifiers(0),
"ex",
treeMaker.Ident(names.fromString("Exception")),
null);
JCTree.JCBlock catchBlock = treeMaker.Block(0L, List.of(
treeMaker.Exec(treeMaker.Apply(
List.nil(),
treeMaker.Select(treeMaker.Ident(names.fromString("ex")),
names.fromString("printStackTrace")),
List.nil()
))
));
JCTree.JCCatch catchClause = treeMaker.Catch(exVar, catchBlock);
JCTree.JCTry tryCatchTree = treeMaker.Try(tryBlock, List.of(catchClause), null);
methodDecl.body = treeMaker.Block(0L, List.of(tryCatchTree));
System.out.println(methodDecl.body.toString());
}
private com.sun.tools.javac.util.Name getNameFromString(String s) {
return names.fromString(s);
}
/**
* 创建变量语句
*
* @param modifiers
* @param name 变量名
* @param varType 变量类型
* @param init 变量初始化语句
* @return
*/
private JCTree.JCVariableDecl createVarDef(JCTree.JCModifiers modifiers, String name, JCTree.JCExpression varType, JCTree.JCExpression init) {
return treeMaker.VarDef(
modifiers,
//名字
getNameFromString(name),
//类型
varType,
//初始化语句
init
);
}
}