目录
1. OpenRewrite是什么?定位?
2. OpenWrite具体如何做?
3. 核心概念释义
3.1 Lossless Semantic Trees (LST) 无损语义树
3.2 访问器(Visitors)
3.3 配方(Recipes)
4. 参考链接
OpenRewrite是一个用于大规模自动化代码重构的框架,通过帮助开发人员自动化地进行代码重构和转换,大大提升了研发效率。
本文主要对OpenRewrite进行简要介绍,更详尽的说明可以参加OpenRewrite官网Introduction to OpenRewrite | OpenRewrite by Moderne。
作为一款开源框架,代码仓库地址见:GitHub - openrewrite/rewrite: Automated mass refactoring of source code.
1. OpenRewrite是什么?定位?
OpenRewrite是一个用于源代码的自动重构开源框架,使开发人员能够有效地消除代码库中的技术债务。
它包括一个自动重构引擎,可以运行预打包的开源重构方案,用于常见的框架迁移、安全修复和风格一致性任务,将您的编码工作从几小时或几天减少到几分钟。构建工具插件如OpenRewrite Gradle插件和OpenRewrite Maven插件帮助您一次在一个代码库上运行这些重构方案。
通过使用OpenRewrite,开发人员可以轻松地应用各种重构规则,以改善代码的可读性、可维护性和性能。它可以帮助开发人员自动化地进行代码转换,减少手动修改代码的工作量,并确保代码的一致性和质量。
总之,OpenRewrite是一个强大的工具,可以帮助开发人员快速、高效地进行代码重构,消除技术债务,提高代码质量和开发效率。
OpenRewrite主要的用途包括但不限于:
- 自动化代码重构
- 框架迁移
- 安全漏洞修复
- 代码技术债消除
- 等等
2. OpenWrite具体如何做?
OpenRewrite的工作原理是对表示源代码的LST(Lossless Semantic Trees)无损语义树进行修改,并将修改后的树输出回源代码。然后,您可以查看代码中的更改并提交。对LST的修改是在访问器(Visitors)中执行的,并将这些访问器聚合到配方(Recipe)中,这里采用了访问者设计模式的方案。
在OpenRewrite中,LST无损语义树是一种抽象语法树(AST)的变体,用于表示特定编程语言的源代码结构。通过解析源代码文件,OpenRewrite将其转换为LST表示形式。然后,访问器可以遍历和修改LST的不同部分,例如添加、删除、替换代码片段,修改变量名等。
配方(Recipe)是一组预定义的或自定义的访问器,它们定义了对LST进行的具体修改操作。这些配方可以针对常见的框架迁移、安全修复和风格一致性任务进行预打包,也可以根据特定需求进行自定义开发。
在执行具体的配方(Recipe)时,OpenRewrite会应用访问器对LST进行修改。修改后的LST将被重新生成为源代码文件,以便您可以查看和审查更改。您可以根据需要进行进一步的修改和调整,然后提交更改后的代码。
总之,OpenRewrite通过对LST进行修改和重新生成源代码,实现了对源代码的自动化重写。它使用访问器来执行具体的修改操作,并将这些访问器聚合到配方(Recipe)中。
3. 核心概念释义
3.1 Lossless Semantic Trees (LST) 无损语义树
LST使用树来表示代码,与传统的抽象语法树(AST)不同,OpenRewrite的LST具有一组独特的特性,使得在代码库中进行准确的转换和搜索成为可能:
OpenRewrite的LST具有以下特点:
1. 类型属性(Type-attributed):每个LST都包含与之相关的类型信息。例如,在源代码中引用一个字段时,源代码可能只是将其称为myField。而OpenRewrite的LST则会包含关于myField的类型信息。
2. 保持格式(Format-preserving):LST在树中保留了LST前后的空白字符,因此可以将树打印出来以重新构建原始的源代码,而不会破坏格式。此外,插入代码的重构操作会对周围代码的本地风格敏感,并匹配本地风格。
通过这些特点,OpenRewrite的LST能够提供更准确和可靠的代码转换和搜索。
类型属性使得在进行代码转换时可以更精确地处理不同类型的代码元素;
保持格式的特性使得转换后的代码保持了原始代码的格式和风格,并提高了代码的可读性。
在Java语言中,下图释义了一个简单的Java类如何表示为LST,并描述LST的层次结构,如下:
- CompilationUnit(编译单元):
在Java的LST中,CompilationUnit(编译单元)是LST的根节点,代表了一个Java源代码文件的整体结构,它包含了文件级别的信息和元素,例如包声明、导入语句、类声明等。
- ClassDeclaration(类声明):表示整个Java类,它包含了类的名称、修饰符、继承关系等信息。
- Block(代码块):由一对花括号(curly braces)以及其中包含的语句(Statements)组成的。Block表示了一段代码的作用域范围,通常用于定义方法体、循环体、条件语句体等。它可以包含多个语句,这些语句按照顺序执行。
VariableDeclarations(变量声明):这是一个LST,表示类中的字段声明、方法参数、局部变量定义等;
- MethodDeclaration(方法声明):这是一个LST,表示类中的方法声明。
- ......
3.2 访问器(Visitors)
在OpenRewrite中,访问器(Visitor)是核心逻辑所在的地方。它确定了应该更新哪些元素以及何时更新。
访问器是一种用于遍历和修改LST的组件。它定义了在遍历LST时要执行的操作,例如查找特定类型的代码元素、修改代码元素的属性或结构等。
在OpenRewrite中,所有的访问器都继承自抽象类TreeVisitor<T extends Tree, P>,并提供了泛型化的visit(T, P)方法;参数化类型T代表访问器将要遍历和转换的LST的类型,第二个参数P是一个额外的、共享的上下文,作为一个访问器在遍历给定的LST时传递给所有的visit方法
OpenRewrite的访问器通过继承TreeVisitor类,并重写visit方法来实现对LST的遍历和转换。通过泛型化的visit方法和参数化类型,访问器可以灵活地处理不同类型的LST,并通过共享的上下文实现数据的共享和传递。
3.3 配方(Recipes)
一个配方(Recipe)代表了一组可以应用于Lossless Semantic Tree的搜索和重构操作,它可以表示一个单独的、独立的操作,也可以与其他配方链接在一起,以实现更大的目标,比如框架迁移。
Recipe是OpenRewrite中的一个核心概念,它定义了对代码进行搜索和重构的具体操作。一个Recipe可以包含多个访问器(Visitors),每个访问器负责执行特定的操作,例如查找特定类型的代码元素、修改代码元素的属性或结构等。
通过将多个Recipe链接在一起,开发人员可以实现复杂的重写逻辑和转换操作。例如,可以使用一个Recipe来查找所有使用过时的API,并将其替换为新的API,然后使用另一个Recipe来调整代码的结构和格式。
配方(Recipe)实际开发实践参见:OpenRewrite:实现一个简单的配方(Recipe)
4. 参考链接
Introduction to OpenRewrite | OpenRewrite by Moderne
Java LST examples | OpenRewrite by Moderne