如何使用带有指令的脚本自动化Java代码重构?

t9aqgxwy  于 2023-03-06  发布在  Java
关注(0)|答案(3)|浏览(155)

如何通过Java代码/Groovy插件以编程方式重构这个类?比方说,我需要:

  • foo.method2重命名为foo.method3
  • myMethod重命名为yourMethod
  • 更改导入的包org.you.core.util.AnotherClassFromExternalPackage
import com.me.core.util.AnotherClassFromExternalPackage;
import com.me.core.util.Foo;

public class MyClass implements AnotherClassFromExternalPackage {

    private final Foo foo;

    public MyClass() {
        this.foo = new Foo();
    }

    @Override
    public long myMethod() {
        return foo.method2();
    }
}

如何创建一个脚本来解析代码,应用语法转换并使用给定的指令保存它?
上面的代码只是一个例子。更大的问题是,我有很多项目使用相同的外部库。有时他们发布了一个新版本,其中包含了破坏性的更改,这在依赖关系迁移后破坏了当前代码。我必须每2周更新10多个项目的依赖关系到最新版本。我需要编写一个脚本来自动修复这些破坏性的更改。理想情况下,逐个应用代码转换。

p8h8hvxi

p8h8hvxi1#

听起来像是OpenRewrite的工作。标准的方法,例如,重命名一个包是可用的。你也可以写你自己的方法,它利用一个访问者模式在一个基于树的源代码表示上(这将保留,例如,缩进)。
您可以使用Maven或Gradle执行重写。
例如,开始页面中的变更包配置如下所示:

type: specs.openrewrite.org/v1beta/recipe
name: com.yourorg.VetToVeterinary
recipeList:
  - org.openrewrite.java.ChangePackage:
    oldPackageName: org.springframework.samples.petclinic.vet
    newPackageName: org.springframework.samples.petclinic.veterinary
envsm3lx

envsm3lx2#

不基于Groovy(但其他建议“OpenRewrite”或“IntelliJ”的答案也不基于Groovy)。
OP所要求的是一个program transformation system (PTS),它可以让他编写自定义转换规则。大多数PTS系统都提供了对目标语言AST的访问......你可以通过编写程序访问者来编写自定义规则,程序访问者可以在树周围攀爬,匹配和拼接各个树节点。显然也是开放重写。
这是一种笨拙的方法,主要是因为AST的细节是大量的,而且有点随意,而你的树爬行代码必须知道所有这些。更多细节请参见program_transforms on AST vs surface syntax。理想情况下,你应该使用编程语言的表层语法编写转换,让PTS负责对实际AST进行匹配和替换。
我们的DMS Software Reengineering Toolkit可以让你做到这一点。op想要做的转换是这样编码的:

Domain Java~v11; -- specifies which specific Java dialect grammar is relevant

rule rename_foo(p:access_path_prefix): access_path -> access_path
  = "\p foo.method2" -> "\p foo.method3";

rule rename_myMethod(p:access_path_prefix): access_path -> access_path
  = "\p myMethod" -> "\p your_method";

rule change_import_AnotherClassFromExternalPackage: import_statement -> import_statement
  = "import org.you.core.util.AnotherClassFromExternalPackage"
    -> "import com.me.core.util.AnotherClassFromExternalPackage";

ruleset my_patches = 
   { rename_foo, 
     rename_myMethod, 
     change_import_AnotherClassFromExternalPackage
   }

Domain关键字告诉DMS使用哪种语法来解析源文本,包括特定的方言(Java 6与Java 11不同)。
命名各个规则(例如rename_foo)。参数列表(例如p:access_path_prefix)允许指定命名的语法片段(例如p),该命名的语法片段可以匹配语法类别(例如access_path_prefix)的任意树。每个规则指定它是从一个语法片段到另一个语法片段的Map->;对于这些规则,源和目标语法类别是相同的(例如access_path)。
每个规则还指定Map的详细信息(= "*match*" -> "*replacement*")其中match和replacement是分别与源和目标语法类别匹配的有效表面语法模式。使用引号的原因是将规则语法与源/目标语言语法分隔开(例如Java)。匹配模式"\p foo.method2"匹配任意路径前缀(由点跟随的标识符序列或空的特殊情况,如Java语法所定义),后跟access_path foo.method2的结尾(如op所需)。替换模式与access_path_前缀p,其后是接入路径的改变的末端foo.method3
ruleset mypatches将各个规则收集到一个组中,DMS可以在任何地方应用这些规则。
用户可以运行为Java~v11配置的DMS RuleRewrite引擎,将其指向法律的的Java文件,然后应用mypatches规则集以实现OP所需的内容。DMS解析文件以构建AST,解析规则以构造匹配所需的AST,匹配规则AST并替换匹配的AST(这样你就不必用过程树黑客来做这些事情了)完成后,DMS重新生成转换后的源文本,保留缩进、注解等。
因此,应用感兴趣的规则是一个机械的过程,这些规则相当容易编写,因为它们使用(Java)表面语法,而不是爬树原语。
这些都是相当简单的例子,我们已经使用DMS在Java和C++之间进行了大量的重写,甚至将COBOL转换为Java。

4zcjmb1e

4zcjmb1e3#

我会有一个Excel表格,列像这样,

1.使用Apache POI之类的库读取Excel文件并提取所需信息(项目名称、包名称、类名、方法名称和字段名称)。
1.使用Eclipse JDT之类的库来解析源代码并构建AST。
1.遍历AST并标识与指定的类、方法和字段对应的节点。
1.将所需的修改应用于已识别的AST节点。
1.从更新的AST生成修改的源代码。

相关问题