From 9bf1ba46b6dd3ce1ff975eed01bd3b96119c67c8 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Fri, 26 Jan 2024 21:34:36 +0100 Subject: [PATCH] Use getFirst() instead of stream().findFirst().orElseThrow() --- .../java/migrate/util/ListFirstAndLast.java | 7 +- .../java/migrate/util/StreamFindFirst.java | 82 +++++++++++++++++++ .../migrate/util/ListFirstAndLastTest.java | 2 - .../migrate/util/StreamFindFirstTest.java | 82 +++++++++++++++++++ 4 files changed, 166 insertions(+), 7 deletions(-) create mode 100644 src/main/java/org/openrewrite/java/migrate/util/StreamFindFirst.java create mode 100644 src/test/java/org/openrewrite/java/migrate/util/StreamFindFirstTest.java diff --git a/src/main/java/org/openrewrite/java/migrate/util/ListFirstAndLast.java b/src/main/java/org/openrewrite/java/migrate/util/ListFirstAndLast.java index 00d19aefe4..9056dd53c5 100644 --- a/src/main/java/org/openrewrite/java/migrate/util/ListFirstAndLast.java +++ b/src/main/java/org/openrewrite/java/migrate/util/ListFirstAndLast.java @@ -15,10 +15,7 @@ */ package org.openrewrite.java.migrate.util; -import org.openrewrite.ExecutionContext; -import org.openrewrite.Preconditions; -import org.openrewrite.Recipe; -import org.openrewrite.TreeVisitor; +import org.openrewrite.*; import org.openrewrite.java.JavaIsoVisitor; import org.openrewrite.java.MethodMatcher; import org.openrewrite.java.search.UsesJavaVersion; @@ -109,7 +106,7 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu .withParameterNames(null) .withParameterTypes(null); } - return mi.withName(mi.getName().withSimpleName(operation + firstOrLast)) + return mi.withName(mi.getName().withSimpleName(operation + firstOrLast).withType(newMethodType)) .withArguments(arguments) .withMethodType(newMethodType); } diff --git a/src/main/java/org/openrewrite/java/migrate/util/StreamFindFirst.java b/src/main/java/org/openrewrite/java/migrate/util/StreamFindFirst.java new file mode 100644 index 0000000000..dcecf7ad57 --- /dev/null +++ b/src/main/java/org/openrewrite/java/migrate/util/StreamFindFirst.java @@ -0,0 +1,82 @@ +/* + * 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.util; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Preconditions; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.search.UsesJavaVersion; +import org.openrewrite.java.search.UsesMethod; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.TypeUtils; + +public class StreamFindFirst extends Recipe { + private static final MethodMatcher COLLECTION_STREAM_MATCHER = new MethodMatcher("java.util.Collection stream()", true); + private static final MethodMatcher STREAM_FIND_FIRST_MATCHER = new MethodMatcher("java.util.stream.Stream findFirst()", true); + private static final MethodMatcher OPTIONAL_OR_ELSE_THROW_MATCHER = new MethodMatcher("java.util.Optional orElseThrow()", true); + + @Override + public String getDisplayName() { + return "Use `getFirst()` instead of `stream().findFirst().orElseThrow()`"; + } + + @Override + public String getDescription() { + return "For SequencedCollections, use `collection.getFirst()` instead of `collection.stream().findFirst().orElseThrow()`."; + } + + @Override + public TreeVisitor getVisitor() { + JavaIsoVisitor javaIsoVisitor = new JavaIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); + + if (!OPTIONAL_OR_ELSE_THROW_MATCHER.matches(mi) || !(mi.getSelect() instanceof J.MethodInvocation)) { + return mi; + } + J.MethodInvocation optional = (J.MethodInvocation) mi.getSelect(); + if (!STREAM_FIND_FIRST_MATCHER.matches(optional) || !(optional.getSelect() instanceof J.MethodInvocation)) { + return mi; + } + J.MethodInvocation stream = (J.MethodInvocation) optional.getSelect(); + if (!COLLECTION_STREAM_MATCHER.matches(stream) || + !TypeUtils.isOfClassType(stream.getSelect().getType(), "java.util.SequencedCollection")) { + return mi; + } + JavaType.Method methodType = stream.getMethodType().withName("getFirst"); + return stream + .withName(stream.getName().withSimpleName("getFirst").withType(methodType)) + .withMethodType(methodType) + .withPrefix(mi.getPrefix()); + } + + + }; + return Preconditions.check( + Preconditions.and( + new UsesJavaVersion<>(21), + new UsesMethod<>(COLLECTION_STREAM_MATCHER), + new UsesMethod<>(STREAM_FIND_FIRST_MATCHER), + new UsesMethod<>(OPTIONAL_OR_ELSE_THROW_MATCHER) + ), + javaIsoVisitor); + } +} diff --git a/src/test/java/org/openrewrite/java/migrate/util/ListFirstAndLastTest.java b/src/test/java/org/openrewrite/java/migrate/util/ListFirstAndLastTest.java index 94bd5cd37e..dc005c5348 100644 --- a/src/test/java/org/openrewrite/java/migrate/util/ListFirstAndLastTest.java +++ b/src/test/java/org/openrewrite/java/migrate/util/ListFirstAndLastTest.java @@ -26,11 +26,9 @@ import static org.openrewrite.java.Assertions.java; import static org.openrewrite.java.Assertions.javaVersion; - @Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/243") @EnabledForJreRange(min = JRE.JAVA_21) class ListFirstAndLastTest implements RewriteTest { - @Override public void defaults(RecipeSpec spec) { spec.recipe(new ListFirstAndLast()) diff --git a/src/test/java/org/openrewrite/java/migrate/util/StreamFindFirstTest.java b/src/test/java/org/openrewrite/java/migrate/util/StreamFindFirstTest.java new file mode 100644 index 0000000000..923359534f --- /dev/null +++ b/src/test/java/org/openrewrite/java/migrate/util/StreamFindFirstTest.java @@ -0,0 +1,82 @@ +/* + * 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.util; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; +import static org.openrewrite.java.Assertions.javaVersion; + +@EnabledForJreRange(min = JRE.JAVA_21) +class StreamFindFirstTest implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec + .recipe(new StreamFindFirst()) + .parser(JavaParser.fromJavaVersion().logCompilationWarningsAndErrors(true)) + .allSources(src -> src.markers(javaVersion(21))); + } + + @Test + void sequencedCollection() { + rewriteRun( + //language=java + java( + """ + import java.util.*; + + class Foo { + void bar(SequencedCollection collection) { + String first = collection.stream().findFirst().orElseThrow(); + } + } + """, + """ + import java.util.*; + + class Foo { + void bar(SequencedCollection collection) { + String first = collection.getFirst(); + } + } + """ + ) + ); + } + + @Test + void regularCollection() { + rewriteRun( + //language=java + java( + """ + import java.util.*; + + class Foo { + void bar(Collection collection) { + String first = collection.stream().findFirst().orElseThrow(); + } + } + """ + ) + ); + } +}