Java Parser介绍

[toc]

Java Parser基本信息

JavaParser是一个Java库,用于将Java源代码解析为抽象语法树(AST),在AST基础上进行类型推断分析,支持修改AST从而生成新的Java文件内容(解析修改生成 Java 代码)。官网:https://javaparser.org

通过使用JavaParser,你可以执行以下任务:

  • 分析Java源代码并获取详细信息。
  • 修改现有的Java代码,并生成新的Java源代码。
  • 自动化代码转换和重构任务。
  • 构建静态代码分析工具。

JavaParser的特点

  • 基于ANTLR 4的高性能解析器。ANTLR 4是一个流行的词法分析器和语法分析器生成器,用于构建语言、工具和服务。
  • 完全符合Java语法规则。JavaParser遵循最新的Java语言规范,支持Java 8至17的所有版本。
  • 简洁易用的API。JavaParser提供了清晰、直观的API,使您可以轻松地在Java代码上工作。
  • 广泛的生态系统。JavaParser与其他流行的技术(如Junit、Mockito和Checkstyle)兼容,拥有丰富的生态系统。
  • 开源免费。JavaParser是根据Apache 2.0许可证发布的,可以自由使用和扩展。

核心组件

JavaParser 的主要构成由以下几个组件组成:

  1. Lexer(词法分析器):词法分析器的作用是读取源代码文本,并将其分解成一系列的词法单元(tokens),如关键字、标识符、字面量、运算符等。这是解析过程的第一步。
    img
    通常不需要显式调用,JavaParser将具体的细节实现隐藏在内部,调用方只需要使用api即可完成源码到AST的转换。具体可以翻阅com.github.javaparser.GeneratedJavaParser

  2. Parser(语法解析器):语法分析器接收词法分析器生成的tokens,并根据Java语言的语法规则将它们组合成各种语法结构,如表达式、语句、类定义等。这个过程构建出一个抽象语法树(AST)。com.github.javaparser.JavaParser 这是最常用的类。

  3. AST(抽象语法树):AST 是 JavaParser 的核心数据结构,它以层次化的方式表示了源代码的结构。AST 由一系列的节点组成,每个节点表示源代码中的一个元素,如类、方法、字段、表达式等。每个节点都包含有关该元素的信息,例如名称、类型、修饰符等。

    AST是后续操作(如遍历、分析、修改)的基础,也是使用方操作最频繁的类。com.github.javaparser.ast.CompilationUnit是一个非常重要的类,它代表了Java源代码文件的根节点,是这个结构的抽象表示,包含整个文件的结构,例如:

    • 包声明(Package Declaration)

    • 导入声明(Imports)

    • 类型声明(Type Declarations),这可能是类、接口、枚举或注解

    • 注释(Comments)

    • 任何顶级的注解

    通过操作CompilationUnit提供的公有方法,可以访问和修改文件中的元素。包括:

    • 获取和设置包声明

    • 获取和添加导入声明

    • 获取和添加类型声明

    • 获取和添加注释

    • 使用访问者模式来遍历AST中的节点

img

  1. Visitors(访问器):顾名思义,这是一个采用访问者模式设计的组件,可以用于遍历和操作 AST 。开发者可以编写自定义的 Visitors,通过遍历 AST 来访问特定类型的节点,执行代码分析、重构、生成等任务。 com.github.javaparser.ast.visitor.GenericVisitorcom.github.javaparser.ast.visitor.VoidVisitor这两个访问器提供了默认实现,如果需要自定义访问器,可以继承它们来实现自己的业务逻辑。

  2. Printer(打印器):Printer 用于将 AST 转换回 Java 源代码的字符串表示形式。它可以将修改后的 AST 打印回原始源代码文件,或将 AST 打印为格式化的代码字符串。

核心类

CompilationUnit

Javaparser解析java代码后会生成AST(abstract syntax tree,抽象语法树),CompilationUnit(编译单元)是每个java文件被解析后直接生成的对象,是读取和操作java文件的入口。CompilationUnit包含了整棵AST的Node,可以理解为AST的根节点。

在这里插入图片描述

上图根据代码画出了CompilationUnit的结构中包含了三个子节点,一个package申明,一个import申明,一个类定义。上图并没有完整的描述整个语法树,绿色三角形的部分被省略了,下图展示了省略的MethodDeclatation部分:

img

通过其四个节点,我们可看出其返回类型是void,方法名是main,方法参数是String args,以及其方法体:

img

Node

AST的Node,对于java中的类、接口、注解、方法、入参、赋值语句、注释、if条件、注释等都是一种Node,如果Node表示的代码块能继续细化分割,就在其子节点列表NodeList中,Node是读取和操作AST的基本单元。

Node的部分子类:

在这里插入图片描述

这些Node类和其表示的java代码(每个类的注释中有,官方文档附录B中有全部的Node类及其示例)

在这里插入图片描述

Visitor

Javaparser使用访问者模式来访问或修改Node,当需要修改Node时,Node本身不需要额外增加方法,而是通过创建一个Visitor,在Visitor中定义好需要修改什么,用Node调用方法接收我们创建的Visitor完成修改。

Visitable和两类Visitor接口

为了实现这种模式,作者设计了两类接口,一个是Visitable,一个是Visitor(根据有无返回值,分为GenericVisitor和VoidVisitor)。

(1)所有可访问的Node都实现了Visitable接口,这个接口有两个accept方法,用于接收Visitor以及外部参数arg,外部参数可用于收集遍历到的东西。

(2)所有Node实现Visitable接口的方法都是传递自身实例和外部arg。

(3)针对不同类型Node,实现GenericVisitor接口中对应的方法就能访问这种类型的Node。

在这里插入图片描述

也就是说我们用Node实例调用它的accept方法,传入一个编写好的Visitor,Visitor中的实现方法就能访问这个Node。

VoidVisitorAdapter

当我们只需要访问java代码而不需要做修改时,直接继承VoidVisitorAdapter。这个抽象类对VoidVisitor做了默认实现,通过递归执行accept方法来达到遍历整个AST的目的。

在这里插入图片描述

上图中对CompilationUnit的import(引包)、module(java高版本模块)、package(所属包)、type(定义的类型class、interface、enum、annotation)、comment(注释)分别遍历执行accept,而其中的每一种Node又会遍历子节点执行accept。

例如下图访问class和interface的ClassOrInterfaceDeclaration的方法,分别遍历它涵盖的节点。

在这里插入图片描述

ModifierVisitor

与VoidVisitorAdapter不同的是,ModifierVisitor继承带返回值的GenericVisitor,其返回值用于返回修改后的节点。如下图所示,遍历各项子节点以后,将返回值作为修改后的对象重新赋值。

在这里插入图片描述


参考:
https://cloud.tencent.com/developer/news/740798
https://blog.csdn.net/gitblog_00089/article/details/136705307
https://blog.csdn.net/qq_40800602/article/details/134446052
https://blog.csdn.net/JDDTechTalk/article/details/136053986