You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenRewrite执行顺序问题:依赖未被添加至POM文件

OpenRewrite Recipe跨文件执行顺序与依赖添加延迟问题的解决方案

先明确核心执行逻辑

OpenRewrite的Recipe执行顺序确实是先给单个文件应用所有Recipe,再处理下一个文件,而非先把某个Recipe跑完所有文件。这种设计是为了保证单个文件内的变更原子性,但会带来跨文件的依赖感知问题——比如Java文件刚生成了AssertJ的代码,但处理POM文件时,依赖检测逻辑还是基于初始代码快照,看不到刚新增的AssertJ引用,所以第一次运行不会自动添加依赖,第二次扫描到变更后的代码才会生效。

为什么你的Hamcrest转AssertJ场景会复现

你使用的org.openrewrite.java.testing.hamcrest.MigrateHamcrestToAssertJ,其依赖添加逻辑是靠扫描代码中是否存在AssertJ使用触发的。第一次执行时,Java文件的AssertJ代码是刚修改生成的,但POM文件的处理流程已经走完(每个文件按顺序处理,单个文件先跑完全部Recipe),依赖检测逻辑没捕捉到新的引用,所以不会添加依赖。第二次执行时,代码已是修改后的状态,扫描就能检测到引用,自然会添加依赖。

可行的解决方案

1. 拆分执行阶段,分两次运行

把OpenRewrite的执行拆成两步:

  • 第一步:仅运行代码迁移类Recipe(如MigrateHamcrestToAssertJ),先将所有Java文件的Hamcrest代码改为AssertJ
  • 第二步:运行依赖添加类Recipe(如AddDependency),此时代码已是修改后的状态,依赖检测能准确触发

在Maven中可配置两个独立的执行块,分别指定不同的Recipe集合:

<build>
    <plugins>
        <plugin>
            <groupId>org.openrewrite.maven</groupId>
            <artifactId>rewrite-maven-plugin</artifactId>
            <version>5.40.0</version>
            <executions>
                <!-- 第一阶段:仅做代码迁移 -->
                <execution>
                    <id>migrate-hamcrest-to-assertj</id>
                    <goals>
                        <goal>run</goal>
                    </goals>
                    <configuration>
                        <recipes>
                            <recipe>org.openrewrite.java.testing.hamcrest.MigrateHamcrestToAssertJ</recipe>
                        </recipes>
                    </configuration>
                </execution>
                <!-- 第二阶段:添加AssertJ依赖 -->
                <execution>
                    <id>add-assertj-dependency</id>
                    <goals>
                        <goal>run</goal>
                    </goals>
                    <configuration>
                        <recipes>
                            <recipe>org.openrewrite.maven.AddDependency</recipe>
                        </recipes>
                        <data>
                            <groupId>org.assertj</groupId>
                            <artifactId>assertj-core</artifactId>
                            <version>3.24.2</version>
                        </data>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

2. 自定义Recipe,绑定代码迁移和依赖添加

自己编写一个组合Recipe,在代码迁移完成后主动扫描Java文件的变更,再触发依赖添加。这样能保证在同一个执行周期内完成两个动作,无需重复运行。

核心逻辑示例(Java自定义Recipe):

public class MigrateHamcrestToAssertJWithDep extends Recipe {
    @Override
    public String getDisplayName() {
        return "迁移Hamcrest到AssertJ并自动添加依赖";
    }

    @Override
    public TreeVisitor<?, ExecutionContext> getVisitor() {
        // 先执行官方迁移Recipe
        TreeVisitor<?, ExecutionContext> migrateVisitor = new MigrateHamcrestToAssertJ().getVisitor();
        // 迁移完成后检查Java文件的AssertJ引用,再给POM添加依赖
        return TreeVisitor.postVisit(migrateVisitor, (tree, ctx) -> {
            if (tree instanceof MavenPom) {
                // 遍历所有Java文件,检查是否存在AssertJ导入
                boolean hasAssertJ = ctx.getFindSourceFiles().findByType(JavaSourceFile.class)
                        .stream()
                        .map(JavaSourceFile.class::cast)
                        .anyMatch(javaFile -> javaFile.getImports().stream()
                                .anyMatch(imp -> imp.getQualifiedName().startsWith("org.assertj")));
                if (hasAssertJ) {
                    // 调用AddDependency逻辑添加依赖
                    return new AddDependency(
                            "org.assertj", "assertj-core", "3.24.2",
                            null, null, null
                    ).getVisitor().visit(tree, ctx);
                }
            }
            return tree;
        });
    }
}

3. 参考JUnit5迁移Recipe的实现思路

org.openrewrite.java.testing.junit5.JUnit4to5Migration之所以能自动添加依赖,是因为它在迁移Java代码的同时,主动给POM文件添加依赖,而非等待后续的依赖扫描。你可以参考它的源码,把这种“主动触发”的逻辑用到你的场景中——比如在修改Java文件的Recipe里,直接触发POM的依赖添加动作,跳过依赖扫描环节。

多模块项目的额外提示

如果是多模块Maven项目,要确保Recipe能遍历所有模块的文件,或者使用org.openrewrite.maven.MavenRecipes统一处理父POM和子模块,避免子模块的代码变更未被父POM的依赖逻辑感知到。


内容的提问来源于stack exchange,提问作者Philippe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 14:38:18