-
Notifications
You must be signed in to change notification settings - Fork 78
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rewrite
Stream.collect(Collectors.toUnmodifiableList())
to `Stream.…
…toList()` (#293) * Add recipe to rewrite java 11 `Stream.collect(Collectors.toUnmodifiableList())` and optionally `Stream.collect(Collectors.toList())` to java 16 `Stream.toList()` * Polish * Apply suggestions from code review --------- Co-authored-by: Westerlaken, H.L. (Laurens) <laurens.westerlaken@devolksbank.nl> Co-authored-by: Tim te Beek <tim@moderne.io> Co-authored-by: Tim te Beek <timtebeek@gmail.com>
- Loading branch information
1 parent
c3f924f
commit 467c10f
Showing
3 changed files
with
290 additions
and
0 deletions.
There are no files selected for viewing
106 changes: 106 additions & 0 deletions
106
src/main/java/org/openrewrite/java/migrate/util/ReplaceStreamCollectWithToList.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
/* | ||
* Copyright 2023 the original author or authors. | ||
* <p> | ||
* 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 | ||
* <p> | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* <p> | ||
* 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 lombok.RequiredArgsConstructor; | ||
import lombok.Value; | ||
import org.openrewrite.*; | ||
import org.openrewrite.internal.lang.Nullable; | ||
import org.openrewrite.java.JavaIsoVisitor; | ||
import org.openrewrite.java.JavaTemplate; | ||
import org.openrewrite.java.MethodMatcher; | ||
import org.openrewrite.java.search.UsesJavaVersion; | ||
import org.openrewrite.java.search.UsesMethod; | ||
import org.openrewrite.java.tree.Expression; | ||
import org.openrewrite.java.tree.J; | ||
|
||
import java.time.Duration; | ||
import java.util.Collections; | ||
import java.util.HashSet; | ||
import java.util.Set; | ||
|
||
@Value | ||
public class ReplaceStreamCollectWithToList extends Recipe { | ||
|
||
private static final MethodMatcher STREAM_COLLECT = new MethodMatcher("java.util.stream.Stream collect(java.util.stream.Collector)"); | ||
private static final MethodMatcher COLLECT_TO_UNMODIFIABLE_LIST = new MethodMatcher("java.util.stream.Collectors toUnmodifiableList()"); | ||
private static final MethodMatcher COLLECT_TO_LIST = new MethodMatcher("java.util.stream.Collectors toList()"); | ||
|
||
@Option(displayName = "Convert mutable `Collectors.toList()` to immutable", | ||
description = "Also replace `Stream.collect(Collectors.toList())` with `Stream.toList()`. " + | ||
"*BEWARE*: Attempts to modify the returned list, result in an `UnsupportedOperationException`!", | ||
required = false) | ||
@Nullable | ||
Boolean convertToList; | ||
|
||
@Override | ||
public String getDisplayName() { | ||
return "Replace `Stream.collect(Collectors.toUnmodifiableList())` with `Stream.toList()`"; | ||
} | ||
|
||
@Override | ||
public String getDescription() { | ||
return "Replace `Stream.collect(Collectors.toUnmodifiableList())` with Java 16+ `Stream.toList()`. " + | ||
"Also replaces `Stream.collect(Collectors.toList())` if `convertToList` is set to `true`."; | ||
} | ||
|
||
@Override | ||
public Duration getEstimatedEffortPerOccurrence() { | ||
return Duration.ofMinutes(1); | ||
} | ||
|
||
@Override | ||
public Set<String> getTags() { | ||
return new HashSet<>(Collections.singletonList("RSPEC-6204")); | ||
} | ||
|
||
@Override | ||
public TreeVisitor<?, ExecutionContext> getVisitor() { | ||
return Preconditions.check( | ||
Preconditions.and( | ||
new UsesJavaVersion<>(16), | ||
new UsesMethod<>(STREAM_COLLECT), | ||
Preconditions.or( | ||
new UsesMethod<>(COLLECT_TO_UNMODIFIABLE_LIST), | ||
new UsesMethod<>(COLLECT_TO_LIST)) | ||
), | ||
new ReplaceCollectorToListVisitor(Boolean.TRUE.equals(convertToList))); | ||
} | ||
|
||
@RequiredArgsConstructor | ||
private static final class ReplaceCollectorToListVisitor extends JavaIsoVisitor<ExecutionContext> { | ||
private static final JavaTemplate template = JavaTemplate | ||
.builder("#{any(java.util.stream.Stream)}.toList()") | ||
.build(); | ||
private final boolean convertToList; | ||
|
||
@Override | ||
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { | ||
J.MethodInvocation result = super.visitMethodInvocation(method, ctx); | ||
if (!STREAM_COLLECT.matches(method)) { | ||
return result; | ||
} | ||
Expression command = method.getArguments().get(0); | ||
if (COLLECT_TO_UNMODIFIABLE_LIST.matches(command) | ||
|| convertToList && COLLECT_TO_LIST.matches(command)) { | ||
maybeRemoveImport("java.util.stream.Collectors"); | ||
J.MethodInvocation toList = template.apply(updateCursor(result), result.getCoordinates().replace(), result.getSelect()); | ||
return toList.getPadding().withSelect(result.getPadding().getSelect()); | ||
} | ||
return result; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
183 changes: 183 additions & 0 deletions
183
src/test/java/org/openrewrite/java/migrate/util/ReplaceStreamCollectWithToListTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
/* | ||
* Copyright 2023 the original author or authors. | ||
* <p> | ||
* 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 | ||
* <p> | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* <p> | ||
* 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.openrewrite.DocumentExample; | ||
import org.openrewrite.test.RecipeSpec; | ||
import org.openrewrite.test.RewriteTest; | ||
|
||
import static org.openrewrite.java.Assertions.java; | ||
import static org.openrewrite.java.Assertions.javaVersion; | ||
|
||
class ReplaceStreamCollectWithToListTest implements RewriteTest { | ||
|
||
@Override | ||
public void defaults(RecipeSpec spec) { | ||
spec | ||
.recipe(new ReplaceStreamCollectWithToList(false)) | ||
.allSources(s -> s.markers(javaVersion(17))); | ||
} | ||
|
||
@Test | ||
@DocumentExample | ||
void replacesToUnmodifiableList() { | ||
rewriteRun( | ||
//language=java | ||
java( | ||
""" | ||
import java.util.stream.Collectors; | ||
import java.util.stream.Stream; | ||
import java.util.List; | ||
class Example { | ||
List<String> test(Stream<String> stream) { | ||
return stream.collect(Collectors.toUnmodifiableList()); | ||
} | ||
} | ||
""", | ||
""" | ||
import java.util.stream.Stream; | ||
import java.util.List; | ||
class Example { | ||
List<String> test(Stream<String> stream) { | ||
return stream.toList(); | ||
} | ||
} | ||
""" | ||
) | ||
); | ||
} | ||
|
||
@Test | ||
void doesNotReplaceToListByDefault() { | ||
rewriteRun( | ||
//language=java | ||
java( | ||
""" | ||
import java.util.stream.Collectors; | ||
import java.util.stream.Stream; | ||
import java.util.List; | ||
class Example { | ||
List<String> test(Stream<String> stream) { | ||
return stream.collect(Collectors.toList()); | ||
} | ||
} | ||
""" | ||
) | ||
); | ||
} | ||
|
||
@Test | ||
void doesReplaceToListWhenFlagSetToTrue() { | ||
rewriteRun( | ||
recipeSpec -> recipeSpec.recipe(new ReplaceStreamCollectWithToList(true)), | ||
//language=java | ||
java( | ||
""" | ||
import java.util.stream.Collectors; | ||
import java.util.stream.Stream; | ||
import java.util.List; | ||
class Example { | ||
List<String> test(Stream<String> stream) { | ||
return stream.collect(Collectors.toList()); | ||
} | ||
} | ||
""", | ||
""" | ||
import java.util.stream.Stream; | ||
import java.util.List; | ||
class Example { | ||
List<String> test(Stream<String> stream) { | ||
return stream.toList(); | ||
} | ||
} | ||
""" | ||
) | ||
); | ||
} | ||
|
||
@Test | ||
void retainWhitespace() { | ||
rewriteRun( | ||
//language=java | ||
java( | ||
""" | ||
import java.util.stream.Collectors; | ||
import java.util.stream.Stream; | ||
import java.util.List; | ||
class Example { | ||
List<String> test(Stream<String> stream) { | ||
return stream | ||
.collect(Collectors.toUnmodifiableList()); | ||
} | ||
} | ||
""", | ||
""" | ||
import java.util.stream.Stream; | ||
import java.util.List; | ||
class Example { | ||
List<String> test(Stream<String> stream) { | ||
return stream | ||
.toList(); | ||
} | ||
} | ||
""" | ||
) | ||
); | ||
} | ||
|
||
@Test | ||
void retainComment() { | ||
rewriteRun( | ||
//language=java | ||
java( | ||
""" | ||
import java.util.stream.Collectors; | ||
import java.util.stream.Stream; | ||
import java.util.List; | ||
class Example { | ||
List<String> test(Stream<String> stream) { | ||
return stream | ||
// Convert to list | ||
.collect(Collectors.toUnmodifiableList()); | ||
} | ||
} | ||
""", | ||
""" | ||
import java.util.stream.Stream; | ||
import java.util.List; | ||
class Example { | ||
List<String> test(Stream<String> stream) { | ||
return stream | ||
// Convert to list | ||
.toList(); | ||
} | ||
} | ||
""" | ||
) | ||
); | ||
} | ||
|
||
} |