From 6c91647195761d0c81fba446a6ceab05d3ab64d1 Mon Sep 17 00:00:00 2001 From: KaushikV1017 Date: Fri, 13 Feb 2026 15:38:31 -0800 Subject: [PATCH 1/2] Fix ChangeType recipe's path resolution logic for substring and directory match cases --- .../org/openrewrite/java/ChangeTypeTest.java | 49 +++++++++++++++++++ .../java/org/openrewrite/java/ChangeType.java | 8 ++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/ChangeTypeTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/ChangeTypeTest.java index 8462e5820e7..8ab8ca75b9d 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/ChangeTypeTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/ChangeTypeTest.java @@ -1427,6 +1427,55 @@ public class Target { ); } + @Test + void doNotRenameFileWhenPathAlreadyHasNewTypeName() { + rewriteRun( + spec -> spec.recipe(new ChangeType("a.A", "a.ANew", false)), + java( + """ + package a; + public class A { + } + """, + """ + package a; + public class ANew { + } + """, + spec -> spec.path("a/ANew.java").afterRecipe(cu -> { + assertThat(PathUtils.separatorsToUnix(cu.getSourcePath().toString())).isEqualTo("a/ANew.java"); + assertThat(TypeUtils.isOfClassType(cu.getClasses().getFirst().getType(), "a.ANew")).isTrue(); + }) + ) + ); + } + + @Test + void doNotCorruptPathWhenDirectoryMatchesOldFqn() { + String pathWithOriginalDir = "src/main/java/com/example/Original/Original.java"; + rewriteRun( + spec -> spec.recipe(new ChangeType("com.example.Original", "com.example.NewName", false)), + java( + """ + package com.example; + public class Original { + } + """, + """ + package com.example; + public class NewName { + } + """, + spec -> spec.path(pathWithOriginalDir).afterRecipe(cu -> { + String path = PathUtils.separatorsToUnix(cu.getSourcePath().toString()); + assertThat(path).isEqualTo(pathWithOriginalDir); + assertThat(path).doesNotContain("NewName/Original.java"); + assertThat(TypeUtils.isOfClassType(cu.getClasses().getFirst().getType(), "com.example.NewName")).isTrue(); + }) + ) + ); + } + @Issue("https://github.com/openrewrite/rewrite/issues/1904") @Test void updateImportPrefixWithEmptyPackage() { diff --git a/rewrite-java/src/main/java/org/openrewrite/java/ChangeType.java b/rewrite-java/src/main/java/org/openrewrite/java/ChangeType.java index 4d4887e4faf..372f31002c3 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/ChangeType.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/ChangeType.java @@ -647,11 +647,15 @@ public J visit(@Nullable Tree tree, ExecutionContext ctx) { } String oldPath = cu.getSourcePath().toString().replace('\\', '/'); - // The old FQN must exist in the path. String oldFqn = fqnToPath(originalType.getFullyQualifiedName()); String newFqn = fqnToPath(targetType.getFullyQualifiedName()); - Path newPath = Paths.get(oldPath.replaceFirst(oldFqn, newFqn)); + // Only update the path when it ends with oldFqn + ".java" (this file is the old type's source). + String newPathStr = oldPath; + if (oldPath.endsWith(oldFqn + ".java")) { + newPathStr = oldPath.substring(0, oldPath.length() - (oldFqn + ".java").length()) + newFqn + ".java"; + } + Path newPath = Paths.get(newPathStr); if (updatePath(cu, oldPath, newPath.toString())) { cu = cu.withSourcePath(newPath); } From f73e15785545fa16de1f4645a36cafa9da6a49d5 Mon Sep 17 00:00:00 2001 From: KaushikV1017 Date: Tue, 17 Feb 2026 16:49:05 -0800 Subject: [PATCH 2/2] Modified recipe to be extension agnostic, support different file types --- .../src/main/java/org/openrewrite/java/ChangeType.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/ChangeType.java b/rewrite-java/src/main/java/org/openrewrite/java/ChangeType.java index 372f31002c3..3937b19e3fc 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/ChangeType.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/ChangeType.java @@ -649,11 +649,11 @@ public J visit(@Nullable Tree tree, ExecutionContext ctx) { String oldPath = cu.getSourcePath().toString().replace('\\', '/'); String oldFqn = fqnToPath(originalType.getFullyQualifiedName()); String newFqn = fqnToPath(targetType.getFullyQualifiedName()); - - // Only update the path when it ends with oldFqn + ".java" (this file is the old type's source). + int lastDot = oldPath.lastIndexOf('.'); + String extension = lastDot >= 0 ? oldPath.substring(lastDot) : ""; String newPathStr = oldPath; - if (oldPath.endsWith(oldFqn + ".java")) { - newPathStr = oldPath.substring(0, oldPath.length() - (oldFqn + ".java").length()) + newFqn + ".java"; + if (!extension.isEmpty() && oldPath.endsWith(oldFqn + extension)) { + newPathStr = oldPath.substring(0, oldPath.length() - (oldFqn + extension).length()) + newFqn + extension; } Path newPath = Paths.get(newPathStr); if (updatePath(cu, oldPath, newPath.toString())) {