Java中的屠龙之术——如何修改语法树

Lombok经常用,但是你知道它的原理是什么吗?,和Lombok经常用,但是你知道它的原理是什么吗?(二)两篇文章中介绍了关于Lombok的底层原理,其实总结为一句话来说就是在编译期通过改变抽象语法树而实现的。上面两篇文章已经讲了抽象语法树的相关知识点,如果有不清楚的可以看一下。

本篇涉及到的所有代码都在github上面有

本篇涉及到的所有代码都在github上面有

本篇涉及到的所有代码都在github上面有

在网上关于如何修改Java的抽象语法树的相关API文档并不多,于是本篇记录一下相关的知识点,以便随后查阅。

JCTree的介绍

JCTree是语法树元素的基类,包含一个重要的字段pos,该字段用于指明当前语法树节点(JCTree)在语法树中的位置,因此我们不能直接用new关键字来创建语法树节点,即使创建了也没有意义。此外,结合访问者模式,将数据结构与数据的处理进行解耦,部分源码如下:

public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {

    public int pos = -1;

    ...

    public abstract void accept(JCTree.Visitor visitor);

    ...
}

我们可以看到JCTree是一个抽象类,这里重点介绍几个JCTree的子类

  1. JCStatement:声明语法树节点,常见的子类如下
    • JCBlock:语句块语法树节点
    • JCReturn:return语句语法树节点
    • JCClassDecl:类定义语法树节点
    • JCVariableDecl:字段/变量定义语法树节点
  2. JCMethodDecl:方法定义语法树节点
  3. JCModifiers:访问标志语法树节点
  4. JCExpression:表达式语法树节点,常见的子类如下
    • JCAssign:赋值语句语法树节点
    • JCIdent:标识符语法树节点,可以是变量,类型,关键字等等

TreeMaker介绍

TreeMaker用于创建一系列的语法树节点,我们上面说了创建JCTree不能直接使用new关键字来创建,所以Java为我们提供了一个工具,就是TreeMaker,它会在创建时为我们创建的JCTree对象设置pos字段,所以必须使用上下文相关的TreeMaker对象来创建语法树节点。

具体的API介绍可以参照,TreeMakerAPI,接下来着重介绍一下常用的几个方法。

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;
}
  1. flags:访问标志
  2. annotations:注解列表

其中flags可以使用枚举类com.sun.tools.javac.code.Flags来表示,例如我们可以这样用,就生成了下面的访问标志了。

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;
}

  1. mods:访问标志,可以通过TreeMaker.Modifiers来创建
  2. name:类名
  3. typarams:泛型参数列表
  4. extending:父类
  5. implementing:实现的接口
  6. 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 defa
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值