diff --git a/build.gradle.kts b/build.gradle.kts
index af572b74a..367aabb7f 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -35,6 +35,8 @@ dependencies {
runtimeOnly("org.openrewrite:rewrite-java-17")
runtimeOnly("org.openrewrite:rewrite-java-21")
+ runtimeOnly("tech.picnic.error-prone-support:error-prone-contrib:latest.release:recipes")
+
testImplementation("org.junit.jupiter:junit-jupiter-api:latest.release")
testImplementation("org.junit.jupiter:junit-jupiter-params:latest.release")
testImplementation("org.junit-pioneer:junit-pioneer:2.0.0")
diff --git a/src/main/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSize.java b/src/main/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSize.java
new file mode 100644
index 000000000..76398631d
--- /dev/null
+++ b/src/main/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSize.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Moderne Source Available License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://docs.moderne.io/licensing/moderne-source-available-license
+ *
+ * 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.guava;
+
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Preconditions;
+import org.openrewrite.Recipe;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.java.JavaTemplate;
+import org.openrewrite.java.JavaVisitor;
+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.JavaCoordinates;
+
+public class NoMapsAndSetsWithExpectedSize extends Recipe {
+
+ private static final MethodMatcher NEW_HASHMAP = new MethodMatcher("com.google.common.collect.Maps newHashMapWithExpectedSize(int)", false);
+ private static final MethodMatcher NEW_LINKED_HASHMAP = new MethodMatcher("com.google.common.collect.Maps newLinkedHashMapWithExpectedSize(int)", false);
+ private static final MethodMatcher NEW_HASHSET = new MethodMatcher("com.google.common.collect.Sets newHashSetWithExpectedSize(int)", false);
+ private static final MethodMatcher NEW_LINKED_HASHSET = new MethodMatcher("com.google.common.collect.Sets newLinkedHashSetWithExpectedSize(int)", false);
+
+ @Override
+ public String getDisplayName() {
+ return "Prefer JDK methods for Maps and Sets of an expected size";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Prefer Java 19+ methods to create Maps and Sets of an expected size instead of using Guava methods.";
+ }
+
+ @Override
+ public TreeVisitor, ExecutionContext> getVisitor() {
+ return Preconditions.check(
+ Preconditions.and(
+ new UsesJavaVersion<>(19),
+ Preconditions.or(
+ new UsesMethod<>(NEW_HASHMAP),
+ new UsesMethod<>(NEW_LINKED_HASHMAP),
+ new UsesMethod<>(NEW_HASHSET),
+ new UsesMethod<>(NEW_LINKED_HASHSET)
+ )
+ ),
+ new JavaVisitor() {
+ @Override
+ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
+ J.MethodInvocation j = (J.MethodInvocation) super.visitMethodInvocation(method, ctx);
+ if (NEW_HASHMAP.matches(j)) {
+ maybeRemoveImport("com.google.common.collect.Maps");
+ maybeAddImport("java.util.HashMap");
+ JavaCoordinates coordinates = j.getCoordinates().replace();
+ return JavaTemplate.builder("new HashMap<>(#{any()})")
+ .imports("java.util.HashMap")
+ .build()
+ .apply(getCursor(), coordinates, j.getArguments().toArray());
+ } else if (NEW_LINKED_HASHMAP.matches(j)) {
+ maybeRemoveImport("com.google.common.collect.Maps");
+ maybeAddImport("java.util.LinkedHashMap");
+ JavaCoordinates coordinates = j.getCoordinates().replace();
+ return JavaTemplate.builder("new LinkedHashMap<>(#{any()})")
+ .imports("java.util.LinkedHashMap")
+ .build()
+ .apply(getCursor(), coordinates, j.getArguments().toArray());
+ } else if (NEW_HASHSET.matches(j)) {
+ maybeRemoveImport("com.google.common.collect.Sets");
+ maybeAddImport("java.util.HashSet");
+ JavaCoordinates coordinates = j.getCoordinates().replace();
+ return JavaTemplate.builder("new HashSet<>(#{any()})")
+ .imports("java.util.HashSet")
+ .build()
+ .apply(getCursor(), coordinates, j.getArguments().toArray());
+ } else if (NEW_LINKED_HASHSET.matches(j)) {
+ maybeRemoveImport("com.google.common.collect.Sets");
+ maybeAddImport("java.util.LinkedHashSet");
+ JavaCoordinates coordinates = j.getCoordinates().replace();
+ return JavaTemplate.builder("new LinkedHashSet<>(#{any()})")
+ .imports("java.util.LinkedHashSet")
+ .build()
+ .apply(getCursor(), coordinates, j.getArguments().toArray());
+ }
+ return j;
+ }
+ }
+ );
+ }
+}
diff --git a/src/main/resources/META-INF/rewrite/no-guava.yml b/src/main/resources/META-INF/rewrite/no-guava.yml
index 82f7f90a3..56e204bf7 100644
--- a/src/main/resources/META-INF/rewrite/no-guava.yml
+++ b/src/main/resources/META-INF/rewrite/no-guava.yml
@@ -25,6 +25,8 @@ description: >-
tags:
- guava
recipeList:
+ - org.openrewrite.java.migrate.guava.NoGuavaJava11
+ - org.openrewrite.java.migrate.guava.NoGuavaJava21
- org.openrewrite.java.migrate.guava.NoGuavaCreateTempDir
- org.openrewrite.java.migrate.guava.NoGuavaDirectExecutor
- org.openrewrite.java.migrate.guava.NoGuavaListsNewArrayList
@@ -62,6 +64,8 @@ recipeList:
- org.openrewrite.java.migrate.guava.PreferMathMultiplyExact
- org.openrewrite.java.migrate.guava.NoGuavaAtomicsNewReference
+ - tech.picnic.errorprone.refasterrules.InputStreamRulesRecipes
+
---
type: specs.openrewrite.org/v1beta/recipe
name: org.openrewrite.java.migrate.guava.NoGuavaJava11
@@ -73,8 +77,10 @@ description: >-
tags:
- guava
- java11
+preconditions:
+ - org.openrewrite.java.search.HasJavaVersion:
+ version: "[11,)"
recipeList:
- - org.openrewrite.java.migrate.guava.NoGuava
- org.openrewrite.java.migrate.guava.NoGuavaImmutableListOf
- org.openrewrite.java.migrate.guava.NoGuavaImmutableMapOf
- org.openrewrite.java.migrate.guava.NoGuavaImmutableSetOf
@@ -95,9 +101,13 @@ description: >-
tags:
- guava
- java21
+preconditions:
+ - org.openrewrite.java.search.HasJavaVersion:
+ version: "[21,)"
recipeList:
- - org.openrewrite.java.migrate.guava.NoGuavaJava11
+ - org.openrewrite.java.migrate.guava.NoMapsAndSetsWithExpectedSize
- org.openrewrite.java.migrate.guava.PreferMathClamp
+
---
type: specs.openrewrite.org/v1beta/recipe
name: org.openrewrite.java.migrate.guava.PreferJavaNioCharsetStandardCharsets
diff --git a/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaJava21Test.java b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaJava21Test.java
index f59f1a57d..8eed3f18d 100644
--- a/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaJava21Test.java
+++ b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaJava21Test.java
@@ -17,23 +17,17 @@
import org.junit.jupiter.api.Test;
import org.openrewrite.Issue;
-import org.openrewrite.config.Environment;
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.version;
+import static org.openrewrite.java.Assertions.*;
class NoGuavaJava21Test implements RewriteTest {
@Override
public void defaults(RecipeSpec spec) {
- spec.recipe(
- Environment.builder()
- .scanRuntimeClasspath("org.openrewrite.java.migrate.guava")
- .build()
- .activateRecipes("org.openrewrite.java.migrate.guava.NoGuavaJava21")
- )
+ spec
+ .recipeFromResource("/META-INF/rewrite/no-guava.yml", "org.openrewrite.java.migrate.guava.NoGuava")
.parser(JavaParser.fromJavaVersion().classpath("guava"));
}
@@ -122,32 +116,30 @@ public float testMethod() {
@Test
void noGuavaImmutableOfException() {
rewriteRun(
- version(
- //language=java
- java(
- """
- import com.google.common.collect.ImmutableSet;
- import com.google.common.collect.ImmutableMap;
+ //language=java
+ java(
+ """
+ import com.google.common.collect.ImmutableSet;
+ import com.google.common.collect.ImmutableMap;
- class A {
- public Object getMap() {
- return ImmutableMap.of("key", ImmutableSet.of("value1", "value2"));
- }
- }
- """,
- """
- import com.google.common.collect.ImmutableSet;
+ class A {
+ public Object getMap() {
+ return ImmutableMap.of("key", ImmutableSet.of("value1", "value2"));
+ }
+ }
+ """,
+ """
+ import com.google.common.collect.ImmutableSet;
- import java.util.Map;
+ import java.util.Map;
- class A {
- public Object getMap() {
- return Map.of("key", ImmutableSet.of("value1", "value2"));
- }
- }
- """
- ),
- 21
+ class A {
+ public Object getMap() {
+ return Map.of("key", ImmutableSet.of("value1", "value2"));
+ }
+ }
+ """,
+ spec -> spec.markers(javaVersion(21))
)
);
}
diff --git a/src/test/java/org/openrewrite/java/migrate/guava/PreferJavaUtilObjectsTest.java b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaRefasterTest.java
similarity index 85%
rename from src/test/java/org/openrewrite/java/migrate/guava/PreferJavaUtilObjectsTest.java
rename to src/test/java/org/openrewrite/java/migrate/guava/NoGuavaRefasterTest.java
index f3df9d5b3..7ebd43113 100644
--- a/src/test/java/org/openrewrite/java/migrate/guava/PreferJavaUtilObjectsTest.java
+++ b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaRefasterTest.java
@@ -23,7 +23,7 @@
import static org.openrewrite.java.Assertions.java;
-class PreferJavaUtilObjectsTest implements RewriteTest {
+class NoGuavaRefasterTest implements RewriteTest {
@Override
public void defaults(RecipeSpec spec) {
spec.recipe(new NoGuavaRefasterRecipes())
@@ -184,31 +184,4 @@ Object foo(Object obj) {
)
);
}
-
- @Test
- void moreObjectsFirstNonNullToObjectsRequireNonNullElse() {
- rewriteRun(spec -> spec.recipeFromResource("/META-INF/rewrite/no-guava.yml", "org.openrewrite.java.migrate.guava.NoGuavaJava11"),
- //language=java
- java(
- """
- import com.google.common.base.MoreObjects;
-
- class A {
- Object foo(Object obj) {
- return MoreObjects.firstNonNull(obj, "default");
- }
- }
- """,
- """
- import java.util.Objects;
-
- class A {
- Object foo(Object obj) {
- return Objects.requireNonNullElse(obj, "default");
- }
- }
- """
- )
- );
- }
}
diff --git a/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaTest.java b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaTest.java
index 5701794a8..f53de64aa 100644
--- a/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaTest.java
+++ b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaTest.java
@@ -16,26 +16,52 @@
package org.openrewrite.java.migrate.guava;
import org.junit.jupiter.api.Test;
+import org.openrewrite.DocumentExample;
import org.openrewrite.Issue;
-import org.openrewrite.config.Environment;
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;
class NoGuavaTest implements RewriteTest {
@Override
public void defaults(RecipeSpec spec) {
- spec.recipe(
- Environment.builder()
- .scanRuntimeClasspath("org.openrewrite.java.migrate.guava")
- .build()
- .activateRecipes("org.openrewrite.java.migrate.guava.NoGuava")
- )
+ spec
+ .recipeFromResource("/META-INF/rewrite/no-guava.yml", "org.openrewrite.java.migrate.guava.NoGuava")
.parser(JavaParser.fromJavaVersion().classpath("guava"));
}
+ @DocumentExample
+ @Test
+ void moreObjectsFirstNonNullToObjectsRequireNonNullElse() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import com.google.common.base.MoreObjects;
+
+ class A {
+ Object foo(Object obj) {
+ return MoreObjects.firstNonNull(obj, "default");
+ }
+ }
+ """,
+ """
+ import java.util.Objects;
+
+ class A {
+ Object foo(Object obj) {
+ return Objects.requireNonNullElse(obj, "default");
+ }
+ }
+ """,
+ spec -> spec.markers(javaVersion(11))
+ )
+ );
+ }
+
@Test
@Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/39#issuecomment-910673213")
void preferJavaUtilObjectsHashCode() {
diff --git a/src/test/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSizeTest.java b/src/test/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSizeTest.java
new file mode 100644
index 000000000..aad926d65
--- /dev/null
+++ b/src/test/java/org/openrewrite/java/migrate/guava/NoMapsAndSetsWithExpectedSizeTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Moderne Source Available License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://docs.moderne.io/licensing/moderne-source-available-license
+ *
+ * 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.guava;
+
+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 NoMapsAndSetsWithExpectedSizeTest implements RewriteTest {
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec.recipe(new NoMapsAndSetsWithExpectedSize());
+ }
+
+ @DocumentExample
+ @Test
+ void noMapSetWithExpectedSize() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import com.google.common.collect.Maps;
+ import com.google.common.collect.Sets;
+ import java.util.Map;
+ import java.util.Set;
+
+ class A {
+ void method() {
+ Map a = Maps.newHashMapWithExpectedSize(1);
+ Map b = Maps.newLinkedHashMapWithExpectedSize(1);
+ Set c = Sets.newHashSetWithExpectedSize(1);
+ Set d = Sets.newLinkedHashSetWithExpectedSize(1);
+ }
+ }
+ """,
+ """
+ import java.util.*;
+
+ class A {
+ void method() {
+ Map a = new HashMap<>(1);
+ Map b = new LinkedHashMap<>(1);
+ Set c = new HashSet<>(1);
+ Set d = new LinkedHashSet<>(1);
+ }
+ }
+ """,
+ spec -> spec.markers(javaVersion(21))
+ )
+ );
+ }
+}