diff --git a/rewrite-core/src/main/java/org/openrewrite/SourceFileWithReferences.java b/rewrite-core/src/main/java/org/openrewrite/SourceFileWithReferences.java
new file mode 100644
index 00000000000..d53fa550e7a
--- /dev/null
+++ b/rewrite-core/src/main/java/org/openrewrite/SourceFileWithReferences.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openrewrite;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.jspecify.annotations.Nullable;
+import org.openrewrite.trait.Reference;
+
+import java.util.*;
+
+@Incubating(since = "8.39.0")
+public interface SourceFileWithReferences extends SourceFile {
+
+ References getReferences();
+
+ @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
+ @Getter
+ class References {
+ private final SourceFile sourceFile;
+ private final Set references;
+
+ public Collection findMatches(Reference.Matcher matcher) {
+ return findMatchesInternal(matcher, null);
+ }
+
+ public Collection findMatches(Reference.Matcher matcher, Reference.Kind kind) {
+ return findMatchesInternal(matcher, kind);
+ }
+
+ private List findMatchesInternal(Reference.Matcher matcher, Reference.@Nullable Kind kind) {
+ List list = new ArrayList<>();
+ for (Reference ref : references) {
+ if ((kind == null || ref.getKind().equals(kind)) && ref.matches(matcher) ) {
+ list.add(ref);
+ }
+ }
+ return list;
+ }
+
+ public static References build(SourceFile sourceFile) {
+ Set references = new HashSet<>();
+ ServiceLoader loader = ServiceLoader.load(Reference.Provider.class);
+ loader.forEach(provider -> {
+ if (provider.isAcceptable(sourceFile)) {
+ references.addAll(provider.getReferences(sourceFile));
+ }
+ });
+ return new References(sourceFile, references);
+ }
+ }
+}
diff --git a/rewrite-core/src/main/java/org/openrewrite/SourceFileWithTypeReferences.java b/rewrite-core/src/main/java/org/openrewrite/SourceFileWithTypeReferences.java
deleted file mode 100644
index e4f8974a02b..00000000000
--- a/rewrite-core/src/main/java/org/openrewrite/SourceFileWithTypeReferences.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2024 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openrewrite;
-
-import lombok.AccessLevel;
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-import org.openrewrite.trait.TypeReference;
-
-import java.util.*;
-
-@Incubating(since = "8.39.0")
-public interface SourceFileWithTypeReferences extends SourceFile {
-
- TypeReferences getTypeReferences();
-
- @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
- @Getter
- class TypeReferences {
- private final SourceFile sourceFile;
- private final Set typeReferences;
-
- public Collection findMatches(TypeReference.Matcher matcher) {
- List list = new ArrayList<>();
- for (TypeReference ref : typeReferences) {
- if (ref.matches(matcher)) {
- list.add(ref);
- }
- }
- return list;
- }
-
- public static TypeReferences build(SourceFile sourceFile) {
- Set typeReferences = new HashSet<>();
- ServiceLoader loader = ServiceLoader.load(TypeReference.Provider.class);
- loader.forEach(provider -> {
- if (provider.isAcceptable(sourceFile)) {
- typeReferences.addAll(provider.getTypeReferences(sourceFile));
- }
- });
- return new TypeReferences(sourceFile, typeReferences);
- }
- }
-}
diff --git a/rewrite-core/src/main/java/org/openrewrite/TypeReferenceProvider.java b/rewrite-core/src/main/java/org/openrewrite/TypeReferenceProvider.java
deleted file mode 100644
index b89ea2c767e..00000000000
--- a/rewrite-core/src/main/java/org/openrewrite/TypeReferenceProvider.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2024 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openrewrite;
-
-import org.openrewrite.trait.TypeReference;
-
-import java.util.Set;
-
-public interface TypeReferenceProvider {
-
- Set getTypeReferences(SourceFile sourceFile);
-
- boolean isAcceptable(SourceFile sourceFile);
-}
diff --git a/rewrite-core/src/main/java/org/openrewrite/trait/TypeReference.java b/rewrite-core/src/main/java/org/openrewrite/trait/Reference.java
similarity index 55%
rename from rewrite-core/src/main/java/org/openrewrite/trait/TypeReference.java
rename to rewrite-core/src/main/java/org/openrewrite/trait/Reference.java
index 8d2e89140e6..dbaea758e6f 100644
--- a/rewrite-core/src/main/java/org/openrewrite/trait/TypeReference.java
+++ b/rewrite-core/src/main/java/org/openrewrite/trait/Reference.java
@@ -15,29 +15,48 @@
*/
package org.openrewrite.trait;
-import org.openrewrite.Incubating;
-import org.openrewrite.SourceFile;
-import org.openrewrite.Tree;
+import org.openrewrite.*;
import java.util.Set;
@Incubating(since = "8.39.0")
-public interface TypeReference extends Trait {
+public interface Reference extends Trait {
- String getName();
+ enum Kind {
+ TYPE,
+ PACKAGE
+ }
+
+ Kind getKind();
+
+ String getValue();
+
+ default boolean supportsRename() {
+ return false;
+ }
default boolean matches(Matcher matcher) {
- return matcher.matchesName(getName());
+ return matcher.matchesReference(this);
+ }
+
+ default TreeVisitor rename(Renamer renamer, String replacement) {
+ return renamer.rename(replacement);
}
interface Provider {
- Set getTypeReferences(SourceFile sourceFile);
+ Set getReferences(SourceFile sourceFile);
boolean isAcceptable(SourceFile sourceFile);
}
interface Matcher {
- boolean matchesName(String name);
+ boolean matchesReference(Reference value);
+ }
+
+ interface Renamer {
+ default TreeVisitor rename(String replacement) {
+ throw new UnsupportedOperationException();
+ }
}
}
diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/ChangePackageTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/ChangePackageTest.java
index f21841e0a08..c307f330f27 100644
--- a/rewrite-java-test/src/test/java/org/openrewrite/java/ChangePackageTest.java
+++ b/rewrite-java-test/src/test/java/org/openrewrite/java/ChangePackageTest.java
@@ -30,6 +30,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.openrewrite.java.Assertions.java;
+import static org.openrewrite.xml.Assertions.xml;
@SuppressWarnings("ConstantConditions")
class ChangePackageTest implements RewriteTest {
@@ -1702,4 +1703,26 @@ public enum MyEnum {
)
);
}
+
+ @Test
+ void changePackageInSpringXml() {
+ rewriteRun(
+ spec -> spec.recipe(new ChangePackage("test.type", "test.test.type", true)),
+ xml(
+ """
+
+
+
+
+ """,
+ """
+
+
+
+
+ """
+ )
+ );
+
+ }
}
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 b2234b43a47..752814a7d40 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
@@ -29,6 +29,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.openrewrite.java.Assertions.java;
+import static org.openrewrite.xml.Assertions.xml;
@SuppressWarnings("ConstantConditions")
class ChangeTypeTest implements RewriteTest {
@@ -2019,4 +2020,26 @@ class Letters {
);
}
+ @Test
+ void changeTypeInSpringXml() {
+ rewriteRun(
+ spec -> spec.recipe(new ChangeType("test.type.A", "test.type.B", true)),
+ xml(
+ """
+
+
+
+
+ """,
+ """
+
+
+
+
+ """
+ )
+ );
+
+ }
+
}
diff --git a/rewrite-java/src/main/java/org/openrewrite/java/ChangePackage.java b/rewrite-java/src/main/java/org/openrewrite/java/ChangePackage.java
index 7d28b412ca0..876410cc5cf 100644
--- a/rewrite-java/src/main/java/org/openrewrite/java/ChangePackage.java
+++ b/rewrite-java/src/main/java/org/openrewrite/java/ChangePackage.java
@@ -23,8 +23,10 @@
import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.tree.*;
import org.openrewrite.marker.SearchResult;
+import org.openrewrite.trait.Reference;
import java.nio.file.Paths;
+import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
@@ -83,11 +85,12 @@ public Validated validate() {
@Override
public TreeVisitor, ExecutionContext> getVisitor() {
- JavaIsoVisitor condition = new JavaIsoVisitor() {
+ TreeVisitor, ExecutionContext> condition = new TreeVisitor() {
@Override
- public @Nullable J preVisit(J tree, ExecutionContext ctx) {
+ public @Nullable Tree preVisit(@Nullable Tree tree, ExecutionContext ctx) {
+ stopAfterPreVisit();
if (tree instanceof JavaSourceFile) {
- JavaSourceFile cu = (JavaSourceFile) requireNonNull(tree);
+ JavaSourceFile cu = (JavaSourceFile) tree;
if (cu.getPackageDeclaration() != null) {
String original = cu.getPackageDeclaration().getExpression()
.printTrimmed(getCursor()).replaceAll("\\s", "");
@@ -111,16 +114,48 @@ public TreeVisitor, ExecutionContext> getVisitor() {
}
}
}
- stopAfterPreVisit();
+ } else if (tree instanceof SourceFileWithReferences) {
+ SourceFileWithReferences cu = (SourceFileWithReferences) tree;
+ boolean recursive = Boolean.TRUE.equals(ChangePackage.this.recursive);
+ String recursivePackageNamePrefix = oldPackageName + ".";
+ for (Reference ref : cu.getReferences().getReferences()) {
+ if (ref.getValue().equals(oldPackageName) || recursive && ref.getValue().startsWith(recursivePackageNamePrefix)) {
+ return SearchResult.found(cu);
+ }
+ }
}
- return super.preVisit(tree, ctx);
+ return tree;
}
};
- return Preconditions.check(condition, new ChangePackageVisitor());
+ return Preconditions.check(condition, new TreeVisitor() {
+ @Override
+ public boolean isAcceptable(SourceFile sourceFile, ExecutionContext ctx) {
+ return sourceFile instanceof JavaSourceFile || sourceFile instanceof SourceFileWithReferences;
+ }
+
+ @Override
+ public @Nullable Tree preVisit(@Nullable Tree tree, ExecutionContext ctx) {
+ stopAfterPreVisit();
+ if (tree instanceof JavaSourceFile) {
+ return new JavaChangePackageVisitor().visit(tree, ctx, requireNonNull(getCursor().getParent()));
+ } else if (tree instanceof SourceFileWithReferences) {
+ SourceFileWithReferences sourceFile = (SourceFileWithReferences) tree;
+ SourceFileWithReferences.References references = sourceFile.getReferences();
+ boolean recursive = Boolean.TRUE.equals(ChangePackage.this.recursive);
+ PackageMatcher matcher = new PackageMatcher(oldPackageName, recursive);
+ Map matches = new HashMap<>();
+ for (Reference ref : references.findMatches(matcher)) {
+ matches.put(ref.getTree(), ref);
+ }
+ return new ReferenceChangePackageVisitor(matches, matcher, newPackageName).visit(tree, ctx, requireNonNull(getCursor().getParent()));
+ }
+ return tree;
+ }
+ });
}
- private class ChangePackageVisitor extends JavaVisitor {
+ private class JavaChangePackageVisitor extends JavaVisitor {
private static final String RENAME_TO_KEY = "renameTo";
private static final String RENAME_FROM_KEY = "renameFrom";
@@ -349,4 +384,22 @@ private boolean isTargetRecursivePackageName(String packageName) {
}
}
+
+ @Value
+ @EqualsAndHashCode(callSuper = false)
+ private static class ReferenceChangePackageVisitor extends TreeVisitor {
+ Map matches;
+ Reference.Renamer renamer;
+ String newPackageName;
+
+ @Override
+ public @Nullable Tree preVisit(@Nullable Tree tree, ExecutionContext ctx) {
+ Reference reference = matches.get(tree);
+ if (reference != null && reference.supportsRename()) {
+ return reference.rename(renamer, newPackageName).visit(tree, ctx, getCursor().getParent());
+ }
+ return tree;
+ }
+ }
+
}
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 b3ce211b049..04dd93a0c99 100644
--- a/rewrite-java/src/main/java/org/openrewrite/java/ChangeType.java
+++ b/rewrite-java/src/main/java/org/openrewrite/java/ChangeType.java
@@ -24,6 +24,7 @@
import org.openrewrite.java.tree.*;
import org.openrewrite.marker.Markers;
import org.openrewrite.marker.SearchResult;
+import org.openrewrite.trait.Reference;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -81,22 +82,49 @@ public String getDescription() {
public TreeVisitor, ExecutionContext> getVisitor() {
TreeVisitor, ExecutionContext> condition = new TreeVisitor() {
@Override
- public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) {
+ public @Nullable Tree preVisit(@Nullable Tree tree, ExecutionContext ctx) {
+ stopAfterPreVisit();
if (tree instanceof JavaSourceFile) {
- JavaSourceFile cu = (JavaSourceFile) requireNonNull(tree);
+ JavaSourceFile cu = (JavaSourceFile) tree;
if (!Boolean.TRUE.equals(ignoreDefinition) && containsClassDefinition(cu, oldFullyQualifiedTypeName)) {
return SearchResult.found(cu);
}
return new UsesType<>(oldFullyQualifiedTypeName, true).visitNonNull(cu, ctx);
+ } else if (tree instanceof SourceFileWithReferences) {
+ SourceFileWithReferences cu = (SourceFileWithReferences) tree;
+ return new UsesType<>(oldFullyQualifiedTypeName, true).visitNonNull(cu, ctx);
}
return tree;
}
};
- return Preconditions.check(condition, new ChangeTypeVisitor(oldFullyQualifiedTypeName, newFullyQualifiedTypeName, ignoreDefinition));
+ return Preconditions.check(condition, new TreeVisitor() {
+ @Override
+ public boolean isAcceptable(SourceFile sourceFile, ExecutionContext ctx) {
+ return sourceFile instanceof JavaSourceFile || sourceFile instanceof SourceFileWithReferences;
+ }
+
+ @Override
+ public @Nullable Tree preVisit(@Nullable Tree tree, ExecutionContext ctx) {
+ stopAfterPreVisit();
+ if (tree instanceof JavaSourceFile) {
+ return new JavaChangeTypeVisitor(oldFullyQualifiedTypeName, newFullyQualifiedTypeName, ignoreDefinition).visit(tree, ctx, requireNonNull(getCursor().getParent()));
+ } else if (tree instanceof SourceFileWithReferences) {
+ SourceFileWithReferences sourceFile = (SourceFileWithReferences) tree;
+ SourceFileWithReferences.References references = sourceFile.getReferences();
+ TypeMatcher matcher = new TypeMatcher(oldFullyQualifiedTypeName);
+ Map matches = new HashMap<>();
+ for (Reference ref : references.findMatches(matcher, Reference.Kind.TYPE)) {
+ matches.put(ref.getTree(), ref);
+ }
+ return new ReferenceChangeTypeVisitor(matches, matcher, newFullyQualifiedTypeName).visit(tree, ctx, requireNonNull(getCursor().getParent()));
+ }
+ return tree;
+ }
+ });
}
- private static class ChangeTypeVisitor extends JavaVisitor {
+ private static class JavaChangeTypeVisitor extends JavaVisitor {
private final JavaType.Class originalType;
private final JavaType targetType;
@@ -109,7 +137,7 @@ private static class ChangeTypeVisitor extends JavaVisitor {
private final Map oldNameToChangedType = new IdentityHashMap<>();
private final Set topLevelClassnames = new HashSet<>();
- private ChangeTypeVisitor(String oldFullyQualifiedTypeName, String newFullyQualifiedTypeName, @Nullable Boolean ignoreDefinition) {
+ private JavaChangeTypeVisitor(String oldFullyQualifiedTypeName, String newFullyQualifiedTypeName, @Nullable Boolean ignoreDefinition) {
this.originalType = JavaType.ShallowClass.build(oldFullyQualifiedTypeName);
this.targetType = JavaType.buildType(newFullyQualifiedTypeName);
this.ignoreDefinition = ignoreDefinition;
@@ -527,6 +555,23 @@ private boolean hasNoConflictingImport(@Nullable JavaSourceFile sf) {
}
}
+ @Value
+ @EqualsAndHashCode(callSuper = false)
+ private static class ReferenceChangeTypeVisitor extends TreeVisitor {
+ Map matches;
+ Reference.Renamer renamer;
+ String newFullyQualifiedName;
+
+ @Override
+ public @Nullable Tree preVisit(@Nullable Tree tree, ExecutionContext ctx) {
+ Reference reference = matches.get(tree);
+ if (reference != null && reference.supportsRename()) {
+ return reference.rename(renamer, newFullyQualifiedName).visit(tree, ctx, getCursor().getParent());
+ }
+ return tree;
+ }
+ }
+
private static class ChangeClassDefinition extends JavaIsoVisitor {
private final JavaType.Class originalType;
private final JavaType.Class targetType;
@@ -579,7 +624,7 @@ private boolean updatePath(JavaSourceFile sf, String oldPath, String newPath) {
}
@Override
- public J.@Nullable Package visitPackage(J.Package pkg, ExecutionContext ctx) {
+ public J.@Nullable Package visitPackage(J.Package pkg, ExecutionContext ctx) {
Boolean updatePackage = getCursor().pollNearestMessage("UPDATE_PACKAGE");
if (updatePackage != null && updatePackage) {
String original = pkg.getExpression().printTrimmed(getCursor()).replaceAll("\\s", "");
diff --git a/rewrite-java/src/main/java/org/openrewrite/java/PackageMatcher.java b/rewrite-java/src/main/java/org/openrewrite/java/PackageMatcher.java
new file mode 100644
index 00000000000..c6a88019001
--- /dev/null
+++ b/rewrite-java/src/main/java/org/openrewrite/java/PackageMatcher.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openrewrite.java;
+
+import lombok.Getter;
+import org.jspecify.annotations.Nullable;
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Tree;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.internal.StringUtils;
+import org.openrewrite.trait.Reference;
+import org.openrewrite.xml.tree.Xml;
+
+@Getter
+public class PackageMatcher implements Reference.Renamer, Reference.Matcher {
+
+ private final @Nullable String targetPackage;
+
+ @Getter
+ private final Boolean recursive;
+
+ public PackageMatcher(@Nullable String targetPackage) {
+ this(targetPackage, false);
+ }
+
+ public PackageMatcher(@Nullable String targetPackage, boolean recursive) {
+ this.targetPackage = targetPackage;
+ this.recursive = recursive;
+ }
+
+ @Override
+ public boolean matchesReference(Reference reference) {
+ if (reference.getKind().equals(Reference.Kind.TYPE) || reference.getKind().equals(Reference.Kind.PACKAGE)) {
+ String recursivePackageNamePrefix = targetPackage + ".";
+ if (reference.getValue().equals(targetPackage) || recursive && reference.getValue().startsWith(recursivePackageNamePrefix)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public TreeVisitor rename(String newValue) {
+ return new TreeVisitor() {
+ @Override
+ public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) {
+ if (StringUtils.isNotEmpty(newValue)) {
+ if (tree instanceof Xml.Attribute) {
+ return ((Xml.Attribute) tree).withValue(((Xml.Attribute) tree).getValue().withValue(getReplacement(((Xml.Attribute) tree).getValueAsString(), targetPackage, newValue)));
+ }
+ if (tree instanceof Xml.Tag) {
+ if (((Xml.Tag) tree).getValue().isPresent()) {
+ return ((Xml.Tag) tree).withValue(getReplacement(((Xml.Tag) tree).getValue().get(), targetPackage, newValue));
+ }
+ }
+ }
+ return super.visit(tree, ctx);
+ }
+ };
+ }
+
+ String getReplacement(String value, @Nullable String oldValue, String newValue) {
+ if (oldValue != null) {
+ if (recursive) {
+ return value.replace(oldValue, newValue);
+ } else if (value.startsWith(oldValue) && Character.isUpperCase(value.charAt(oldValue.length() + 1))) {
+ return value.replace(oldValue, newValue);
+ }
+ }
+ return value;
+ }
+
+}
diff --git a/rewrite-java/src/main/java/org/openrewrite/java/TypeMatcher.java b/rewrite-java/src/main/java/org/openrewrite/java/TypeMatcher.java
index 66149adb535..fe5a8cdea9f 100644
--- a/rewrite-java/src/main/java/org/openrewrite/java/TypeMatcher.java
+++ b/rewrite-java/src/main/java/org/openrewrite/java/TypeMatcher.java
@@ -19,6 +19,9 @@
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.jspecify.annotations.Nullable;
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Tree;
+import org.openrewrite.TreeVisitor;
import org.openrewrite.internal.StringUtils;
import org.openrewrite.java.internal.grammar.MethodSignatureLexer;
import org.openrewrite.java.internal.grammar.MethodSignatureParser;
@@ -26,14 +29,15 @@
import org.openrewrite.java.tree.JavaType;
import org.openrewrite.java.tree.TypeTree;
import org.openrewrite.java.tree.TypeUtils;
-import org.openrewrite.trait.TypeReference;
+import org.openrewrite.trait.Reference;
+import org.openrewrite.xml.tree.Xml;
import java.util.regex.Pattern;
import static org.openrewrite.java.tree.TypeUtils.fullyQualifiedNamesAreEqual;
@Getter
-public class TypeMatcher implements TypeReference.Matcher {
+public class TypeMatcher implements Reference.Renamer, Reference.Matcher {
private static final String ASPECTJ_DOT_PATTERN = StringUtils.aspectjNameToPattern(".");
@SuppressWarnings("NotNullFieldNotInitialized")
@@ -112,7 +116,26 @@ private static boolean isPlainIdentifier(MethodSignatureParser.TargetTypePattern
}
@Override
- public boolean matchesName(String name) {
- return matchesTargetTypeName(name);
+ public boolean matchesReference(Reference reference) {
+ return reference.getKind().equals(Reference.Kind.TYPE) && matchesTargetTypeName(reference.getValue());
}
+
+ @Override
+ public TreeVisitor rename(String newValue) {
+ return new TreeVisitor() {
+ @Override
+ public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) {
+ if (StringUtils.isNotEmpty(newValue)) {
+ if (tree instanceof Xml.Attribute) {
+ return ((Xml.Attribute) tree).withValue(((Xml.Attribute) tree).getValue().withValue(newValue));
+ }
+ if (tree instanceof Xml.Tag) {
+ return ((Xml.Tag) tree).withValue(newValue);
+ }
+ }
+ return super.visit(tree, ctx);
+ }
+ };
+ }
+
}
diff --git a/rewrite-java/src/main/java/org/openrewrite/java/search/FindTypes.java b/rewrite-java/src/main/java/org/openrewrite/java/search/FindTypes.java
index 97a468dbffa..9c936327614 100644
--- a/rewrite-java/src/main/java/org/openrewrite/java/search/FindTypes.java
+++ b/rewrite-java/src/main/java/org/openrewrite/java/search/FindTypes.java
@@ -28,6 +28,7 @@
import org.openrewrite.java.tree.*;
import org.openrewrite.marker.SearchResult;
import org.openrewrite.trait.Trait;
+import org.openrewrite.trait.Reference;
import java.util.HashSet;
import java.util.Set;
@@ -68,19 +69,19 @@ public TreeVisitor, ExecutionContext> getVisitor() {
return Preconditions.check(new UsesType<>(fullyQualifiedTypeName, false), new TreeVisitor() {
@Override
public boolean isAcceptable(SourceFile sourceFile, ExecutionContext ctx) {
- return sourceFile instanceof JavaSourceFile || sourceFile instanceof SourceFileWithTypeReferences;
+ return sourceFile instanceof JavaSourceFile || sourceFile instanceof SourceFileWithReferences;
}
@Override
public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) {
if (tree instanceof JavaSourceFile) {
return new JavaSourceFileVisitor(fullyQualifiedType).visit(tree, ctx);
- } else if (tree instanceof SourceFileWithTypeReferences) {
- SourceFileWithTypeReferences sourceFile = (SourceFileWithTypeReferences) tree;
- SourceFileWithTypeReferences.TypeReferences typeReferences = sourceFile.getTypeReferences();
+ } else if (tree instanceof SourceFileWithReferences) {
+ SourceFileWithReferences sourceFile = (SourceFileWithReferences) tree;
+ SourceFileWithReferences.References references = sourceFile.getReferences();
TypeMatcher matcher = new TypeMatcher(fullyQualifiedTypeName);
- Set matches = typeReferences.findMatches(matcher).stream().map(Trait::getTree).collect(Collectors.toSet());
- return new TypeReferenceVisitor(matches).visit(tree, ctx);
+ Set matches = references.findMatches(matcher, Reference.Kind.TYPE).stream().map(Trait::getTree).collect(Collectors.toSet());
+ return new ReferenceVisitor(matches).visit(tree, ctx);
}
return tree;
}
@@ -149,7 +150,7 @@ private static boolean typeMatches(boolean checkAssignability, Pattern pattern,
@Value
@EqualsAndHashCode(callSuper = false)
- private static class TypeReferenceVisitor extends TreeVisitor {
+ private static class ReferenceVisitor extends TreeVisitor {
Set matches;
@Override
diff --git a/rewrite-java/src/main/java/org/openrewrite/java/search/UsesType.java b/rewrite-java/src/main/java/org/openrewrite/java/search/UsesType.java
index 3d348fc8cbe..2e701f37491 100644
--- a/rewrite-java/src/main/java/org/openrewrite/java/search/UsesType.java
+++ b/rewrite-java/src/main/java/org/openrewrite/java/search/UsesType.java
@@ -18,7 +18,7 @@
import lombok.Getter;
import org.jspecify.annotations.Nullable;
import org.openrewrite.SourceFile;
-import org.openrewrite.SourceFileWithTypeReferences;
+import org.openrewrite.SourceFileWithReferences;
import org.openrewrite.Tree;
import org.openrewrite.TreeVisitor;
import org.openrewrite.internal.StringUtils;
@@ -28,7 +28,7 @@
import org.openrewrite.java.tree.JavaType;
import org.openrewrite.java.tree.TypeUtils;
import org.openrewrite.marker.SearchResult;
-import org.openrewrite.trait.TypeReference;
+import org.openrewrite.trait.Reference;
import java.util.function.Predicate;
import java.util.regex.Pattern;
@@ -77,7 +77,7 @@ public UsesType(String fullyQualifiedType, @Nullable Boolean includeImplicit) {
@Override
public boolean isAcceptable(SourceFile sourceFile, P p) {
- return sourceFile instanceof JavaSourceFile || sourceFile instanceof SourceFileWithTypeReferences;
+ return sourceFile instanceof JavaSourceFile || sourceFile instanceof SourceFileWithReferences;
}
@Override
@@ -119,11 +119,11 @@ public boolean isAcceptable(SourceFile sourceFile, P p) {
}
}
}
- } else if (tree instanceof SourceFileWithTypeReferences) {
- SourceFileWithTypeReferences sourceFile = (SourceFileWithTypeReferences) tree;
- SourceFileWithTypeReferences.TypeReferences typeReferences = sourceFile.getTypeReferences();
+ } else if (tree instanceof SourceFileWithReferences) {
+ SourceFileWithReferences sourceFile = (SourceFileWithReferences) tree;
+ SourceFileWithReferences.References references = sourceFile.getReferences();
TypeMatcher matcher = typeMatcher != null ? typeMatcher : new TypeMatcher(fullyQualifiedType);
- for (TypeReference ignored : typeReferences.findMatches(matcher)) {
+ for (Reference ignored : references.findMatches(matcher, Reference.Kind.TYPE)) {
return SearchResult.found(sourceFile);
}
}
diff --git a/rewrite-xml/src/main/java/org/openrewrite/xml/trait/SpringTypeReference.java b/rewrite-xml/src/main/java/org/openrewrite/xml/trait/SpringReference.java
similarity index 61%
rename from rewrite-xml/src/main/java/org/openrewrite/xml/trait/SpringTypeReference.java
rename to rewrite-xml/src/main/java/org/openrewrite/xml/trait/SpringReference.java
index edc9bdc6e83..9b52ae44d42 100644
--- a/rewrite-xml/src/main/java/org/openrewrite/xml/trait/SpringTypeReference.java
+++ b/rewrite-xml/src/main/java/org/openrewrite/xml/trait/SpringReference.java
@@ -17,29 +17,34 @@
import lombok.Value;
import org.jspecify.annotations.Nullable;
-import org.openrewrite.Cursor;
-import org.openrewrite.SourceFile;
-import org.openrewrite.Tree;
+import org.openrewrite.*;
import org.openrewrite.trait.SimpleTraitMatcher;
-import org.openrewrite.trait.TypeReference;
+import org.openrewrite.trait.Reference;
import org.openrewrite.xml.XPathMatcher;
import org.openrewrite.xml.tree.Xml;
import java.util.HashSet;
+import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
@Value
-class SpringTypeReference implements TypeReference {
+class SpringReference implements Reference {
Cursor cursor;
+ Kind kind;
@Override
public Tree getTree() {
- return TypeReference.super.getTree();
+ return Reference.super.getTree();
}
@Override
- public String getName() {
+ public Kind getKind() {
+ return kind;
+ }
+
+ @Override
+ public String getValue() {
if (getTree() instanceof Xml.Attribute) {
Xml.Attribute attribute = (Xml.Attribute) getTree();
return attribute.getValueAsString();
@@ -52,45 +57,58 @@ public String getName() {
throw new IllegalArgumentException("getTree() must be an Xml.Attribute or Xml.Tag: " + getTree().getClass());
}
- static class Matcher extends SimpleTraitMatcher {
- private final Pattern typeReference = Pattern.compile("(?:[a-zA-Z_][a-zA-Z0-9_]*\\.)+[A-Z*][a-zA-Z0-9_]*(?:<[a-zA-Z0-9_,?<> ]*>)?");
+ @Override
+ public boolean supportsRename() {
+ return true;
+ }
+
+ static class Matcher extends SimpleTraitMatcher {
+ private final Pattern referencePattern = Pattern.compile("\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*(?:\\.\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*)*");
private final XPathMatcher classXPath = new XPathMatcher("//@class");
private final XPathMatcher typeXPath = new XPathMatcher("//@type");
+ private final XPathMatcher keyTypeXPath = new XPathMatcher("//@key-type");
+ private final XPathMatcher valueTypeXPath = new XPathMatcher("//@value-type");
private final XPathMatcher tags = new XPathMatcher("//value");
@Override
- protected @Nullable SpringTypeReference test(Cursor cursor) {
+ protected @Nullable SpringReference test(Cursor cursor) {
Object value = cursor.getValue();
if (value instanceof Xml.Attribute) {
Xml.Attribute attrib = (Xml.Attribute) value;
- if (classXPath.matches(cursor) || typeXPath.matches(cursor)) {
- if (typeReference.matcher(attrib.getValueAsString()).matches()) {
- return new SpringTypeReference(cursor);
+ if (classXPath.matches(cursor) || typeXPath.matches(cursor) || keyTypeXPath.matches(cursor) || valueTypeXPath.matches(cursor)) {
+ String stringVal = attrib.getValueAsString();
+ if (referencePattern.matcher(stringVal).matches()) {
+ return new SpringReference(cursor, determineKind(stringVal));
}
}
} else if (value instanceof Xml.Tag) {
Xml.Tag tag = (Xml.Tag) value;
if (tags.matches(cursor)) {
- if (tag.getValue().isPresent() && typeReference.matcher(tag.getValue().get()).matches()) {
- return new SpringTypeReference(cursor);
+ Optional stringVal = tag.getValue();
+ if (stringVal.isPresent() && referencePattern.matcher(stringVal.get()).matches()) {
+ return new SpringReference(cursor, determineKind(stringVal.get()));
}
}
}
return null;
}
+
+ Kind determineKind(String value) {
+ return Character.isUpperCase(value.charAt(value.lastIndexOf('.') + 1)) ? Kind.TYPE : Kind.PACKAGE;
+ }
}
@SuppressWarnings("unused")
- public static class Provider implements TypeReference.Provider {
+ public static class Provider implements Reference.Provider {
@Override
- public Set getTypeReferences(SourceFile sourceFile) {
- Set typeReferences = new HashSet<>();
+ public Set getReferences(SourceFile sourceFile) {
+ Set references = new HashSet<>();
new Matcher().asVisitor(reference -> {
- typeReferences.add(reference);
+ references.add(reference);
return reference.getTree();
}).visit(sourceFile, 0);
- return typeReferences;
+ return references;
}
@Override
diff --git a/rewrite-xml/src/main/java/org/openrewrite/xml/tree/Xml.java b/rewrite-xml/src/main/java/org/openrewrite/xml/tree/Xml.java
index 4e0eb50db4d..1fabf24388c 100755
--- a/rewrite-xml/src/main/java/org/openrewrite/xml/tree/Xml.java
+++ b/rewrite-xml/src/main/java/org/openrewrite/xml/tree/Xml.java
@@ -83,7 +83,7 @@ default boolean isAcceptable(TreeVisitor, P> v, P p) {
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@RequiredArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
- class Document implements Xml, SourceFileWithTypeReferences {
+ class Document implements Xml, SourceFileWithReferences {
@With
@EqualsAndHashCode.Include
UUID id;
@@ -164,25 +164,25 @@ public T service(Class service) {
if (WhitespaceValidationService.class.getName().equals(service.getName())) {
return (T) new XmlWhitespaceValidationService();
}
- return SourceFileWithTypeReferences.super.service(service);
+ return SourceFileWithReferences.super.service(service);
}
@Nullable
@NonFinal
- transient SoftReference typeReferences;
+ transient SoftReference references;
@Transient
@Override
- public TypeReferences getTypeReferences() {
- TypeReferences cache;
- if (this.typeReferences == null) {
- cache = TypeReferences.build(this);
- this.typeReferences = new SoftReference<>(cache);
+ public References getReferences() {
+ References cache;
+ if (this.references == null) {
+ cache = References.build(this);
+ this.references = new SoftReference<>(cache);
} else {
- cache = this.typeReferences.get();
+ cache = this.references.get();
if (cache == null || cache.getSourceFile() != this) {
- cache = TypeReferences.build(this);
- this.typeReferences = new SoftReference<>(cache);
+ cache = References.build(this);
+ this.references = new SoftReference<>(cache);
}
}
return cache;
diff --git a/rewrite-xml/src/main/resources/META-INF/services/org.openrewrite.trait.Reference$Provider b/rewrite-xml/src/main/resources/META-INF/services/org.openrewrite.trait.Reference$Provider
new file mode 100644
index 00000000000..72d76d75ee4
--- /dev/null
+++ b/rewrite-xml/src/main/resources/META-INF/services/org.openrewrite.trait.Reference$Provider
@@ -0,0 +1 @@
+org.openrewrite.xml.trait.SpringReference$Provider
\ No newline at end of file
diff --git a/rewrite-xml/src/main/resources/META-INF/services/org.openrewrite.trait.TypeReference$Provider b/rewrite-xml/src/main/resources/META-INF/services/org.openrewrite.trait.TypeReference$Provider
deleted file mode 100644
index 6f58258f8bc..00000000000
--- a/rewrite-xml/src/main/resources/META-INF/services/org.openrewrite.trait.TypeReference$Provider
+++ /dev/null
@@ -1 +0,0 @@
-org.openrewrite.xml.trait.SpringTypeReference$Provider
\ No newline at end of file
diff --git a/rewrite-xml/src/test/java/org/openrewrite/xml/XmlParserTest.java b/rewrite-xml/src/test/java/org/openrewrite/xml/XmlParserTest.java
index 7eda3abcda9..90bb94ff45f 100755
--- a/rewrite-xml/src/test/java/org/openrewrite/xml/XmlParserTest.java
+++ b/rewrite-xml/src/test/java/org/openrewrite/xml/XmlParserTest.java
@@ -24,6 +24,7 @@
import org.openrewrite.Issue;
import org.openrewrite.test.RecipeSpec;
import org.openrewrite.test.RewriteTest;
+import org.openrewrite.trait.Reference;
import org.openrewrite.xml.tree.Xml;
import java.nio.file.Paths;
@@ -120,7 +121,7 @@ void parseXmlDocument() {
}
@Test
- void javaTypeReferenceDocument() {
+ void javaReferenceDocument() {
rewriteRun(
xml(
"""
@@ -135,13 +136,18 @@ void javaTypeReferenceDocument() {
java.lang.String
+
+ java.lang
+
""",
spec -> spec.afterRecipe(doc -> {
- assertThat(doc.getTypeReferences().getTypeReferences().stream().anyMatch(typeRef -> typeRef.getName().equals("java.lang.String")));
+ assertThat(doc.getReferences().getReferences().stream().anyMatch(typeRef -> typeRef.getValue().equals("java.lang.String")));
+ assertThat(doc.getReferences().getReferences().stream().anyMatch(typeRef -> typeRef.getKind().equals(Reference.Kind.TYPE)));
+ assertThat(doc.getReferences().getReferences().stream().anyMatch(typeRef -> typeRef.getKind().equals(Reference.Kind.PACKAGE)));
})
)
);
diff --git a/rewrite-xml/src/test/java/org/openrewrite/xml/trait/SpringTypeReferenceTest.java b/rewrite-xml/src/test/java/org/openrewrite/xml/trait/SpringReferenceTest.java
similarity index 78%
rename from rewrite-xml/src/test/java/org/openrewrite/xml/trait/SpringTypeReferenceTest.java
rename to rewrite-xml/src/test/java/org/openrewrite/xml/trait/SpringReferenceTest.java
index 5259faf3cf5..d60f5a2e8a9 100644
--- a/rewrite-xml/src/test/java/org/openrewrite/xml/trait/SpringTypeReferenceTest.java
+++ b/rewrite-xml/src/test/java/org/openrewrite/xml/trait/SpringReferenceTest.java
@@ -23,12 +23,12 @@
import static org.openrewrite.xml.Assertions.xml;
-class SpringTypeReferenceTest implements RewriteTest {
+class SpringReferenceTest implements RewriteTest {
@Override
public void defaults(RecipeSpec spec) {
- spec.recipe(RewriteTest.toRecipe(() -> new SpringTypeReference.Matcher()
- .asVisitor(springJavaTypeReference -> SearchResult.found(springJavaTypeReference.getTree(), springJavaTypeReference.getName()))));
+ spec.recipe(RewriteTest.toRecipe(() -> new SpringReference.Matcher()
+ .asVisitor(springJavaTypeReference -> SearchResult.found(springJavaTypeReference.getTree(), springJavaTypeReference.getValue()))));
}
@SuppressWarnings("SpringXmlModelInspection")
@@ -50,6 +50,12 @@ void xmlConfiguration() {
java.lang.String
+
+ java.lang
+
+
+
+
@@ -68,6 +74,12 @@ void xmlConfiguration() {
java.lang.String
+
+ java.lang
+
+
+ -->key-type="java.lang.String" value-type="java.lang.String"/>
+