diff --git a/src/main/java/org/openrewrite/java/migrate/search/FindInternalJavaxApis.java b/src/main/java/org/openrewrite/java/migrate/search/FindInternalJavaxApis.java new file mode 100644 index 0000000000..e18f88713e --- /dev/null +++ b/src/main/java/org/openrewrite/java/migrate/search/FindInternalJavaxApis.java @@ -0,0 +1,90 @@ +/* + * 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.java.migrate.search; + +import lombok.EqualsAndHashCode; +import lombok.RequiredArgsConstructor; +import org.openrewrite.*; +import org.openrewrite.internal.StringUtils; +import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.table.MethodCalls; +import org.openrewrite.java.trait.MethodAccess; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.MethodCall; +import org.openrewrite.marker.SearchResult; + +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +@EqualsAndHashCode(callSuper = false) +public class FindInternalJavaxApis extends Recipe { + + private final transient MethodCalls methodCalls = new MethodCalls(this); + + @Option( + displayName = "Method pattern", + description = "A method pattern that is used to find matching method invocations.", + example = "java.util.List add(..)" + ) + private final String methodPattern; + + @Override + public String getDisplayName() { + return "Find uses of internal javax APIs"; + } + + @Override + public String getDescription() { + return "The libraries that define these APIs will have to be migrated before any of the repositories that use them."; + } + + @Override + public TreeVisitor, ExecutionContext> getVisitor() { + Pattern javaxType = Pattern.compile(StringUtils.aspectjNameToPattern("javax..*")); + return Preconditions.check(new UsesType<>("javax..*", null), new MethodAccess.Matcher(methodPattern) + .asVisitor((ma, ctx) -> { + MethodCall call = ma.getTree(); + JavaType.Method methodType = call.getMethodType(); + if (methodType == null) { + return call; + } + if (methodType.getReturnType() != null && methodType.getReturnType().isAssignableFrom(javaxType)) { + insertRow(ma, ctx, methodType); + return SearchResult.found(call); + } + for (JavaType parameterType : methodType.getParameterTypes()) { + if (parameterType.isAssignableFrom(javaxType)) { + insertRow(ma, ctx, methodType); + return SearchResult.found(call); + } + } + return call; + }) + ); + } + + private void insertRow(MethodAccess ma, ExecutionContext ctx, JavaType.Method methodType) { + methodCalls.insertRow(ctx, new MethodCalls.Row( + ma.getCursor().firstEnclosingOrThrow(SourceFile.class).getSourcePath().toString(), + ma.getTree().printTrimmed(ma.getCursor()), + methodType.getDeclaringType().toString(), + methodType.getName(), + methodType.getParameterTypes().stream().map(String::valueOf) + .collect(Collectors.joining(", ")) + )); + } +} diff --git a/src/test/java/org/openrewrite/java/migrate/search/FindInternalJavaxApisTest.java b/src/test/java/org/openrewrite/java/migrate/search/FindInternalJavaxApisTest.java new file mode 100644 index 0000000000..0f0e30b1f6 --- /dev/null +++ b/src/test/java/org/openrewrite/java/migrate/search/FindInternalJavaxApisTest.java @@ -0,0 +1,110 @@ +/* + * 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.java.migrate.search; + +import org.junit.jupiter.api.Test; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +public class FindInternalJavaxApisTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec.recipe(new FindInternalJavaxApis("org.openrewrite..* *(..)")); + } + + @Test + void returnsJavaxApi() { + //language=java + rewriteRun( + java( + """ + package org.openrewrite; + + interface Api { + javax.xml.stream.StreamFilter test(); + } + """ + ), + java( + """ + package org.openrewrite; + + import javax.xml.stream.StreamFilter; + + class Consumer { + void test(Api api) { + StreamFilter sf = api.test(); + } + } + """, + """ + package org.openrewrite; + + import javax.xml.stream.StreamFilter; + + class Consumer { + void test(Api api) { + StreamFilter sf = /*~~>*/api.test(); + } + } + """ + ) + ); + } + + @Test + void usesJavaxApiInParameter() { + //language=java + rewriteRun( + java( + """ + package org.openrewrite; + + interface Api { + void test(javax.xml.stream.StreamFilter sf); + } + """ + ), + java( + """ + package org.openrewrite; + + import javax.xml.stream.StreamFilter; + + class Consumer { + void test(Api api, StreamFilter sf) { + api.test(sf); + } + } + """, + """ + package org.openrewrite; + + import javax.xml.stream.StreamFilter; + + class Consumer { + void test(Api api, StreamFilter sf) { + /*~~>*/api.test(sf); + } + } + """ + ) + ); + } +}