diff --git a/src/main/java/org/openrewrite/java/migrate/guava/NoGuavaPredicatesAndOr.java b/src/main/java/org/openrewrite/java/migrate/guava/NoGuavaPredicatesAndOr.java
new file mode 100644
index 0000000000..453fc76972
--- /dev/null
+++ b/src/main/java/org/openrewrite/java/migrate/guava/NoGuavaPredicatesAndOr.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2024 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.UsesMethod;
+import org.openrewrite.java.tree.J;
+
+import java.util.Set;
+
+import static java.util.Collections.singleton;
+
+public class NoGuavaPredicatesAndOr extends Recipe {
+ private static final MethodMatcher PREDICATES_AND = new MethodMatcher("com.google.common.base.Predicates and(com.google.common.base.Predicate, com.google.common.base.Predicate)");
+ private static final MethodMatcher PREDICATES_OR = new MethodMatcher("com.google.common.base.Predicates or(com.google.common.base.Predicate, com.google.common.base.Predicate)");
+
+ @Override
+ public String getDisplayName() {
+ return "Prefer `Predicate.and(Predicate)`";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Prefer `Predicate.and(Predicate)` over `Predicates.and(Predicate, Predicate)`.";
+ }
+
+ @Override
+ public Set getTags() {
+ return singleton("guava");
+ }
+
+ @Override
+ public TreeVisitor, ExecutionContext> getVisitor() {
+ TreeVisitor, ExecutionContext> precondition = Preconditions.or(new UsesMethod<>(PREDICATES_AND), new UsesMethod<>(PREDICATES_OR));
+ return Preconditions.check(precondition, new JavaVisitor() {
+ @Override
+ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
+ if (PREDICATES_AND.matches(method)) {
+ maybeRemoveImport("com.google.common.base.Predicate");
+ maybeRemoveImport("com.google.common.base.Predicates");
+ maybeAddImport("java.util.function.Predicate");
+ if (method.getArguments().size() == 2) {
+ return JavaTemplate.builder("#{any(java.util.function.Predicate)}.and(#{any(java.util.function.Predicate)})")
+ .build()
+ .apply(getCursor(),
+ method.getCoordinates().replace(),
+ method.getArguments().get(0),
+ method.getArguments().get(1));
+ }
+ }
+ if (PREDICATES_OR.matches(method)) {
+ maybeRemoveImport("com.google.common.base.Predicate");
+ maybeRemoveImport("com.google.common.base.Predicates");
+ maybeAddImport("java.util.function.Predicate");
+ if (method.getArguments().size() == 2) {
+ return JavaTemplate.builder("#{any(java.util.function.Predicate)}.or(#{any(java.util.function.Predicate)})")
+ .build()
+ .apply(getCursor(),
+ method.getCoordinates().replace(),
+ method.getArguments().get(0),
+ method.getArguments().get(1));
+ }
+ }
+
+ return super.visitMethodInvocation(method, ctx);
+ }
+ });
+ }
+}
diff --git a/src/main/resources/META-INF/rewrite/no-guava.yml b/src/main/resources/META-INF/rewrite/no-guava.yml
index 2e9492b220..ab41a42c67 100644
--- a/src/main/resources/META-INF/rewrite/no-guava.yml
+++ b/src/main/resources/META-INF/rewrite/no-guava.yml
@@ -34,6 +34,7 @@ recipeList:
- org.openrewrite.java.migrate.guava.NoGuavaListsNewCopyOnWriteArrayList
- org.openrewrite.java.migrate.guava.NoGuavaListsNewLinkedList
- org.openrewrite.java.migrate.guava.NoGuavaMapsNewTreeMap
+ - org.openrewrite.java.migrate.guava.NoGuavaPredicatesAndOr
- org.openrewrite.java.migrate.guava.NoGuavaPrimitiveAsList
- org.openrewrite.java.migrate.guava.NoGuavaRefasterRecipes
- org.openrewrite.java.migrate.guava.NoGuavaMapsNewHashMap
diff --git a/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaPredicatesAndOrTest.java b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaPredicatesAndOrTest.java
new file mode 100644
index 0000000000..2589d40a88
--- /dev/null
+++ b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaPredicatesAndOrTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2024 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.InMemoryExecutionContext;
+import org.openrewrite.java.JavaParser;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+
+import static org.openrewrite.java.Assertions.java;
+
+class NoGuavaPredicatesAndOrTest implements RewriteTest {
+
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec
+ .recipe(new NoGuavaPredicatesAndOr())
+ .parser(JavaParser.fromJavaVersion().classpathFromResources(new InMemoryExecutionContext(), "guava"));
+ }
+
+ @DocumentExample
+ @Test
+ void replacePredicatesAnd() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import com.google.common.base.Predicate;
+ import com.google.common.base.Predicates;
+
+ class Test {
+ Predicate isNotNull = s -> s != null;
+ Predicate isNotEmpty = s -> !s.isEmpty();
+ Predicate combined = Predicates.and(isNotNull, isNotEmpty);
+ }
+ """,
+ """
+ import com.google.common.base.Predicate;
+
+ class Test {
+ Predicate isNotNull = s -> s != null;
+ Predicate isNotEmpty = s -> !s.isEmpty();
+ Predicate combined = isNotNull.and(isNotEmpty);
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void replacePredicatesOr() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import com.google.common.base.Predicate;
+ import com.google.common.base.Predicates;
+
+ class Test {
+ Predicate isNotNull = s -> s != null;
+ Predicate isNotEmpty = s -> !s.isEmpty();
+ Predicate combined = Predicates.or(isNotNull, isNotEmpty);
+ }
+ """,
+ """
+ import com.google.common.base.Predicate;
+
+ class Test {
+ Predicate isNotNull = s -> s != null;
+ Predicate isNotEmpty = s -> !s.isEmpty();
+ Predicate combined = isNotNull.or(isNotEmpty);
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void replacePredicatesAndWithMethodReferences() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import com.google.common.base.Predicate;
+ import com.google.common.base.Predicates;
+ import java.util.Objects;
+
+ class Test {
+ Predicate combined = Predicates.and(Objects::nonNull, s -> s.length() > 5);
+ }
+ """,
+ """
+ import com.google.common.base.Predicate;
+ import java.util.Objects;
+
+ class Test {
+ Predicate combined = Objects::nonNull.and(s -> s.length() > 5);
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void replacePredicatesAndNestedCalls() {
+ //language=java
+ rewriteRun(
+ spec -> spec.expectedCyclesThatMakeChanges(2),
+ java(
+ """
+ import com.google.common.base.Predicate;
+ import com.google.common.base.Predicates;
+
+ class Test {
+ Predicate isPositive = n -> n > 0;
+ Predicate isEven = n -> n % 2 == 0;
+ Predicate isLessThan100 = n -> n < 100;
+ Predicate combined = Predicates.and(isPositive, Predicates.and(isEven, isLessThan100));
+ }
+ """,
+ """
+ import com.google.common.base.Predicate;
+
+ class Test {
+ Predicate isPositive = n -> n > 0;
+ Predicate isEven = n -> n % 2 == 0;
+ Predicate isLessThan100 = n -> n < 100;
+ Predicate combined = isPositive.and(isEven.and(isLessThan100));
+ }
+ """
+ )
+ );
+ }
+}