From dbd8cef363a857bc9a64125086af85ff4922c5f4 Mon Sep 17 00:00:00 2001 From: Jente Sondervorst Date: Fri, 6 Mar 2026 10:58:22 +0100 Subject: [PATCH 1/7] Convert ChangeDependency to ScanningRecipe Both delegate recipes (gradle ChangeDependency and maven ChangeDependencyGroupIdAndArtifactId) are now ScanningRecipes, so this wrapper must also be a ScanningRecipe to properly delegate scanning and accumulation to both. The visit logic now tries gradle first, then falls back to maven only if gradle didn't change anything, rather than using else-if which prevented maven from processing files that gradle accepted but didn't modify. --- .../java/dependencies/ChangeDependency.java | 97 +++++++++++++------ 1 file changed, 70 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java b/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java index 937bbe16..2c767598 100644 --- a/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java +++ b/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java @@ -15,47 +15,50 @@ */ package org.openrewrite.java.dependencies; -import lombok.AllArgsConstructor; +import lombok.Data; import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.RequiredArgsConstructor; import org.jspecify.annotations.Nullable; import org.openrewrite.*; -@AllArgsConstructor +import static java.util.Objects.requireNonNull; + @EqualsAndHashCode(callSuper = false) @Getter -public class ChangeDependency extends Recipe { +@RequiredArgsConstructor +public class ChangeDependency extends ScanningRecipe { // Gradle and Maven shared parameters @Option(displayName = "Old group ID", description = "The old group ID to replace. The group ID is the first part of a dependency coordinate 'com.google.guava:guava:VERSION'. Supports glob expressions.", example = "org.openrewrite.recipe") - String oldGroupId; + private final String oldGroupId; @Option(displayName = "Old artifact ID", description = "The old artifact ID to replace. The artifact ID is the second part of a dependency coordinate 'com.google.guava:guava:VERSION'. Supports glob expressions.", example = "rewrite-testing-frameworks") - String oldArtifactId; + private final String oldArtifactId; @Option(displayName = "New group ID", description = "The new group ID to use. Defaults to the existing group ID.", example = "corp.internal.openrewrite.recipe", required = false) @Nullable - String newGroupId; + private final String newGroupId; @Option(displayName = "New artifact ID", description = "The new artifact ID to use. Defaults to the existing artifact ID.", example = "rewrite-testing-frameworks", required = false) @Nullable - String newArtifactId; + private final String newArtifactId; @Option(displayName = "New version", description = "An exact version number or node-style semver selector used to select the version number.", example = "29.X", required = false) @Nullable - String newVersion; + private final String newVersion; @Option(displayName = "Version pattern", description = "Allows version selection to be extended beyond the original Node Semver semantics. So for example," + @@ -63,19 +66,19 @@ public class ChangeDependency extends Recipe { example = "-jre", required = false) @Nullable - String versionPattern; + private final String versionPattern; @Option(displayName = "Override managed version", description = "If the new dependency has a managed version, this flag can be used to explicitly set the version on the dependency. The default for this flag is `false`.", required = false) @Nullable - Boolean overrideManagedVersion; + private final Boolean overrideManagedVersion; @Option(displayName = "Update dependency management", description = "Also update the dependency management section. The default for this flag is `true`.", required = false) @Nullable - Boolean changeManagedDependency; + private final Boolean changeManagedDependency; @Getter final String displayName = "Change Gradle or Maven dependency"; @@ -86,26 +89,47 @@ public class ChangeDependency extends Recipe { @Override public Validated validate(ExecutionContext ctx) { return super.validate(ctx) - .and(((Recipe) new org.openrewrite.gradle.ChangeDependency( - oldGroupId, oldArtifactId, newGroupId, newArtifactId, newVersion, versionPattern, overrideManagedVersion, changeManagedDependency)).validate()) - .and(((Recipe) new org.openrewrite.maven.ChangeDependencyGroupIdAndArtifactId( - oldGroupId, oldArtifactId, newGroupId, newArtifactId, newVersion, versionPattern, overrideManagedVersion, changeManagedDependency)).validate()); + .and(((Recipe) getGradleChangeDependency()).validate()) + .and(((Recipe) getMavenChangeDependency()).validate()); + } + + @Override + public Accumulator getInitialValue(ExecutionContext ctx) { + return new Accumulator( + getMavenChangeDependency().getInitialValue(ctx), + getGradleChangeDependency().getInitialValue(ctx) + ); } @Override - public TreeVisitor getVisitor() { + public TreeVisitor getScanner(Accumulator acc) { + TreeVisitor mavenScanner = getMavenChangeDependency().getScanner(acc.mavenAccumulator); + TreeVisitor gradleScanner = getGradleChangeDependency().getScanner(acc.gradleAccumulator); return new TreeVisitor() { - final TreeVisitor mavenVisitor = new org.openrewrite.maven.ChangeDependencyGroupIdAndArtifactId( - oldGroupId, oldArtifactId, - newGroupId, newArtifactId, - newVersion, versionPattern, - overrideManagedVersion, changeManagedDependency).getVisitor(); - final TreeVisitor gradleVisitor = new org.openrewrite.gradle.ChangeDependency( - oldGroupId, oldArtifactId, - newGroupId, newArtifactId, - newVersion, versionPattern, - overrideManagedVersion, true).getVisitor(); + @Override + public boolean isAcceptable(SourceFile sourceFile, ExecutionContext ctx) { + return mavenScanner.isAcceptable(sourceFile, ctx) || gradleScanner.isAcceptable(sourceFile, ctx); + } + + @Override + public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) { + SourceFile s = (SourceFile) requireNonNull(tree); + if (gradleScanner.isAcceptable(s, ctx)) { + return gradleScanner.visit(tree, ctx); + } + if (mavenScanner.isAcceptable(s, ctx)) { + return mavenScanner.visit(tree, ctx); + } + return tree; + } + }; + } + @Override + public TreeVisitor getVisitor(Accumulator acc) { + TreeVisitor mavenVisitor = getMavenChangeDependency().getVisitor(acc.mavenAccumulator); + TreeVisitor gradleVisitor = getGradleChangeDependency().getVisitor(acc.gradleAccumulator); + return new TreeVisitor() { @Override public boolean isAcceptable(SourceFile sourceFile, ExecutionContext ctx) { return mavenVisitor.isAcceptable(sourceFile, ctx) || gradleVisitor.isAcceptable(sourceFile, ctx); @@ -119,11 +143,30 @@ public boolean isAcceptable(SourceFile sourceFile, ExecutionContext ctx) { SourceFile s = (SourceFile) tree; if (gradleVisitor.isAcceptable(s, ctx)) { s = (SourceFile) gradleVisitor.visitNonNull(s, ctx); - } else if (mavenVisitor.isAcceptable(s, ctx)) { + } + if (s == tree && mavenVisitor.isAcceptable(s, ctx)) { s = (SourceFile) mavenVisitor.visitNonNull(s, ctx); } return s; } }; } + + org.openrewrite.maven.ChangeDependencyGroupIdAndArtifactId getMavenChangeDependency() { + return new org.openrewrite.maven.ChangeDependencyGroupIdAndArtifactId( + oldGroupId, oldArtifactId, newGroupId, newArtifactId, + newVersion, versionPattern, overrideManagedVersion, changeManagedDependency); + } + + org.openrewrite.gradle.ChangeDependency getGradleChangeDependency() { + return new org.openrewrite.gradle.ChangeDependency( + oldGroupId, oldArtifactId, newGroupId, newArtifactId, + newVersion, versionPattern, overrideManagedVersion, true); + } + + @Data + public static final class Accumulator { + private final org.openrewrite.maven.ChangeDependencyGroupIdAndArtifactId.Accumulator mavenAccumulator; + private final org.openrewrite.gradle.ChangeDependency.Accumulator gradleAccumulator; + } } From 360a8ac7b044e91cacca422df0f7bfc5949ad8e8 Mon Sep 17 00:00:00 2001 From: Jente Sondervorst Date: Fri, 6 Mar 2026 11:44:14 +0100 Subject: [PATCH 2/7] Use @Value instead of @Getter + @RequiredArgsConstructor --- .../java/dependencies/ChangeDependency.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java b/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java index 2c767598..108adb3b 100644 --- a/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java +++ b/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java @@ -17,16 +17,14 @@ import lombok.Data; import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.RequiredArgsConstructor; +import lombok.Value; import org.jspecify.annotations.Nullable; import org.openrewrite.*; import static java.util.Objects.requireNonNull; +@Value @EqualsAndHashCode(callSuper = false) -@Getter -@RequiredArgsConstructor public class ChangeDependency extends ScanningRecipe { // Gradle and Maven shared parameters @Option(displayName = "Old group ID", @@ -80,11 +78,9 @@ public class ChangeDependency extends ScanningRecipe validate(ExecutionContext ctx) { From a5cf3c6ebafd267d5ec49a05150738f981087a87 Mon Sep 17 00:00:00 2001 From: Jente Sondervorst Date: Fri, 6 Mar 2026 11:45:42 +0100 Subject: [PATCH 3/7] Remove redundant private final, already implied by @Value --- .../java/dependencies/ChangeDependency.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java b/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java index 108adb3b..874f39f8 100644 --- a/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java +++ b/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java @@ -30,33 +30,33 @@ public class ChangeDependency extends ScanningRecipe Date: Fri, 6 Mar 2026 11:46:55 +0100 Subject: [PATCH 4/7] Remove s == tree guard from visit logic --- .../org/openrewrite/java/dependencies/ChangeDependency.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java b/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java index 874f39f8..c8bb8f36 100644 --- a/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java +++ b/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java @@ -140,7 +140,7 @@ public boolean isAcceptable(SourceFile sourceFile, ExecutionContext ctx) { if (gradleVisitor.isAcceptable(s, ctx)) { s = (SourceFile) gradleVisitor.visitNonNull(s, ctx); } - if (s == tree && mavenVisitor.isAcceptable(s, ctx)) { + if (mavenVisitor.isAcceptable(s, ctx)) { s = (SourceFile) mavenVisitor.visitNonNull(s, ctx); } return s; From 15aa96e3ce843f49ee876bd4374e969b87ac7587 Mon Sep 17 00:00:00 2001 From: Jente Sondervorst Date: Fri, 6 Mar 2026 12:02:47 +0100 Subject: [PATCH 5/7] Revert to @Getter + @RequiredArgsConstructor to avoid making class final @Value makes the class final which is a breaking change for any existing subclasses. --- .../java/dependencies/ChangeDependency.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java b/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java index c8bb8f36..950202b2 100644 --- a/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java +++ b/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java @@ -17,46 +17,48 @@ import lombok.Data; import lombok.EqualsAndHashCode; -import lombok.Value; +import lombok.Getter; +import lombok.RequiredArgsConstructor; import org.jspecify.annotations.Nullable; import org.openrewrite.*; import static java.util.Objects.requireNonNull; -@Value @EqualsAndHashCode(callSuper = false) +@Getter +@RequiredArgsConstructor public class ChangeDependency extends ScanningRecipe { // Gradle and Maven shared parameters @Option(displayName = "Old group ID", description = "The old group ID to replace. The group ID is the first part of a dependency coordinate 'com.google.guava:guava:VERSION'. Supports glob expressions.", example = "org.openrewrite.recipe") - String oldGroupId; + final String oldGroupId; @Option(displayName = "Old artifact ID", description = "The old artifact ID to replace. The artifact ID is the second part of a dependency coordinate 'com.google.guava:guava:VERSION'. Supports glob expressions.", example = "rewrite-testing-frameworks") - String oldArtifactId; + final String oldArtifactId; @Option(displayName = "New group ID", description = "The new group ID to use. Defaults to the existing group ID.", example = "corp.internal.openrewrite.recipe", required = false) @Nullable - String newGroupId; + final String newGroupId; @Option(displayName = "New artifact ID", description = "The new artifact ID to use. Defaults to the existing artifact ID.", example = "rewrite-testing-frameworks", required = false) @Nullable - String newArtifactId; + final String newArtifactId; @Option(displayName = "New version", description = "An exact version number or node-style semver selector used to select the version number.", example = "29.X", required = false) @Nullable - String newVersion; + final String newVersion; @Option(displayName = "Version pattern", description = "Allows version selection to be extended beyond the original Node Semver semantics. So for example," + @@ -64,19 +66,19 @@ public class ChangeDependency extends ScanningRecipe Date: Fri, 6 Mar 2026 12:04:23 +0100 Subject: [PATCH 6/7] Make displayName and description final --- .../org/openrewrite/java/dependencies/ChangeDependency.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java b/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java index 950202b2..a0989c8e 100644 --- a/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java +++ b/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java @@ -80,9 +80,9 @@ public class ChangeDependency extends ScanningRecipe validate(ExecutionContext ctx) { From 52453f0dc0ee3c9d6a29c275aa9c06ebd328bfe4 Mon Sep 17 00:00:00 2001 From: Jente Sondervorst Date: Fri, 6 Mar 2026 12:06:56 +0100 Subject: [PATCH 7/7] Match UpgradeDependencyVersion field style: private final + explicit @Getter on displayName/description --- .../java/dependencies/ChangeDependency.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java b/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java index a0989c8e..2b5e78d4 100644 --- a/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java +++ b/src/main/java/org/openrewrite/java/dependencies/ChangeDependency.java @@ -32,33 +32,33 @@ public class ChangeDependency extends ScanningRecipe