Ragnarok Note

Articles in the Hack category

Project Lacie Initiate

Motivation

我记得去年在组内介绍Annotation和Annotation Process Tool的时候,当时不少小伙伴都认为这个是一个非常棒的工具,用来做代码生成非常合适,但是也存在不少问题,主要的争论点在于,对于大型的项目,其代码量非常大,无论是在IDE内或者在命令行中进行编译,即使只是普通的增量编译,打包,也需要耗上非常长的时间。而普通的APT则需要每次都先拉起一次编译过程,因为实际上整个Annotation Processing是Java编译中的一个步骤,另外如果在Annotation Processing的过程中另外产生了新的代码的话,还需要重新编译生成的代码,这会导致整个编译过程变得更加漫长,如下图,为Java源码编译的过程,摘自OpenJDK官网。

于是,后续我就逐渐开始想方法实现有一个类似Annotation Processor的API的工具,但并不需要拉起Javac进行编译,只需要输入源码即可,然后由开发者自行定义生成代码的规则,即可完成APT的功能。

Research

要实现这样的一个工具,最先迫切的就是需要一个语法解析器,这样子才能从源码中提取出所需要的信息。当时候的想法是自己来实现Tokenizer和Parser(真庆幸大学的时候教编译原理的灭绝大法师的训练,我还记得怎么写哈哈哈哈),但很快我就找到了JavaCC这个工具,这玩意可以说是Java编译器的生成工具,实际上Javac的前端也是这个东西来生成的。但是JavaCC生成的代码非常乱并且其API并不是很好用。当时候我想当JDK中一定是有单独Javac前端独立出来的,于是我又找到了JDK中的tools …

使用JDK的Parser来解析Java源代码

在JDK中,自带了一套相关的编译API,可以在Java中发起编译流程,解析Java源文件然后获取其语法树,在JDK的tools.jar(OSX下可以在/Library/Java/JavaVirtualMachines/jdk_version/Contents/Home/lib中找到)中包含着这整套API,但是这却不是Oracle和OpenJDK发布中的公开API,因此对于这套API,并没有官方的正式文档来进行说明。但是,也有不少项目利用了这套API来做了不少事情,例如大名鼎鼎的lombok使用了这套API在Annotation Processing阶段修改了源代码中的语法树,最终结果相当于直接在源文件中插入了新的代码!

由于这套API目前缺少相关文档,使用起来比较困难,例如,解析源代码中的所有变量,并打印出来:

public class JavaParser {

    private static final String path = "User.java";

    private JavacFileManager fileManager;
    private JavacTool javacTool;

    public JavaParser() {
        Context …