Skip to content

Commit 808ddc1

Browse files
timtebeekclaude
andauthored
Support varargs for Predicates.and() and Predicates.or() (#901)
* Support varargs for Predicates.and() and Predicates.or() This commit extends NoGuavaPredicatesAndOr recipe to handle any number of parameters (varargs) for Predicates.and() and Predicates.or() methods. Changes: - Updated MethodMatcher to match varargs using (..) pattern - Implemented chaining logic to convert multiple parameters into chained .and()/.or() calls (e.g., and(a,b,c) → a.and(b).and(c)) - Added tests for 3+ parameter cases from issue #893 - Replaced problematic method reference test with lambda-based test Fixes #893 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * Add support for method references as first predicate When the first argument to Predicates.and() or Predicates.or() is a method reference, wrap it with a cast to enable calling .and()/.or() on it. Example: Before: Predicates.and(Objects::nonNull, s -> s.length() > 5) After: ((Predicate<String>) Objects::nonNull).and(s -> s.length() > 5) Changes: - Detect J.MemberReference as first argument - Extract parameterized type information - Build cast template with proper type string - Added test case for method reference scenario 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * Minimize implementation --------- Co-authored-by: Claude <[email protected]>
1 parent 29759f4 commit 808ddc1

File tree

2 files changed

+126
-26
lines changed

2 files changed

+126
-26
lines changed

src/main/java/org/openrewrite/java/migrate/guava/NoGuavaPredicatesAndOr.java

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,19 @@
2222
import org.openrewrite.java.JavaTemplate;
2323
import org.openrewrite.java.JavaVisitor;
2424
import org.openrewrite.java.MethodMatcher;
25+
import org.openrewrite.java.ShortenFullyQualifiedTypeReferences;
2526
import org.openrewrite.java.search.UsesMethod;
27+
import org.openrewrite.java.tree.Expression;
2628
import org.openrewrite.java.tree.J;
2729

30+
import java.util.List;
2831
import java.util.Set;
2932

3033
import static java.util.Collections.singleton;
3134

3235
public class NoGuavaPredicatesAndOr extends Recipe {
33-
private static final MethodMatcher PREDICATES_AND = new MethodMatcher("com.google.common.base.Predicates and(com.google.common.base.Predicate, com.google.common.base.Predicate)");
34-
private static final MethodMatcher PREDICATES_OR = new MethodMatcher("com.google.common.base.Predicates or(com.google.common.base.Predicate, com.google.common.base.Predicate)");
36+
private static final MethodMatcher PREDICATES_AND = new MethodMatcher("com.google.common.base.Predicates and(..)");
37+
private static final MethodMatcher PREDICATES_OR = new MethodMatcher("com.google.common.base.Predicates or(..)");
3538

3639
@Override
3740
public String getDisplayName() {
@@ -55,34 +58,40 @@ public TreeVisitor<?, ExecutionContext> getVisitor() {
5558
@Override
5659
public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
5760
if (PREDICATES_AND.matches(method)) {
58-
maybeRemoveImport("com.google.common.base.Predicate");
59-
maybeRemoveImport("com.google.common.base.Predicates");
60-
maybeAddImport("java.util.function.Predicate");
61-
if (method.getArguments().size() == 2) {
62-
return JavaTemplate.builder("#{any(java.util.function.Predicate)}.and(#{any(java.util.function.Predicate)})")
63-
.build()
64-
.apply(getCursor(),
65-
method.getCoordinates().replace(),
66-
method.getArguments().get(0),
67-
method.getArguments().get(1));
68-
}
61+
return handlePredicatesMethod(method, "and");
6962
}
7063
if (PREDICATES_OR.matches(method)) {
71-
maybeRemoveImport("com.google.common.base.Predicate");
72-
maybeRemoveImport("com.google.common.base.Predicates");
73-
maybeAddImport("java.util.function.Predicate");
74-
if (method.getArguments().size() == 2) {
75-
return JavaTemplate.builder("#{any(java.util.function.Predicate)}.or(#{any(java.util.function.Predicate)})")
76-
.build()
77-
.apply(getCursor(),
78-
method.getCoordinates().replace(),
79-
method.getArguments().get(0),
80-
method.getArguments().get(1));
81-
}
64+
return handlePredicatesMethod(method, "or");
8265
}
8366

8467
return super.visitMethodInvocation(method, ctx);
8568
}
69+
70+
private J handlePredicatesMethod(J.MethodInvocation method, String operation) {
71+
List<Expression> arguments = method.getArguments();
72+
if (arguments.size() < 2) {
73+
return method;
74+
}
75+
76+
maybeRemoveImport("com.google.common.base.Predicates");
77+
78+
// Build the chain: first.operation(second).operation(third)...
79+
Expression result = arguments.get(0);
80+
81+
// If the first argument is a method reference, wrap it with a cast
82+
if (result instanceof J.MemberReference && result.getType() != null) {
83+
String typeString = result.getType().toString().replace("com.google.common.base.", "");
84+
result = JavaTemplate.apply("((" + typeString + ") #{any()})", getCursor(), method.getCoordinates().replace(), result);
85+
}
86+
for (int i = 1; i < arguments.size(); i++) {
87+
result = JavaTemplate.apply("#{any(java.util.function.Predicate)}." + operation + "(#{any(java.util.function.Predicate)})",
88+
getCursor(), method.getCoordinates().replace(), result, arguments.get(i));
89+
}
90+
91+
doAfterVisit(ShortenFullyQualifiedTypeReferences.modifyOnly(result));
92+
return result;
93+
}
94+
8695
});
8796
}
8897
}

src/test/java/org/openrewrite/java/migrate/guava/NoGuavaPredicatesAndOrTest.java

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.junit.jupiter.api.Test;
1919
import org.openrewrite.DocumentExample;
2020
import org.openrewrite.InMemoryExecutionContext;
21+
import org.openrewrite.Issue;
2122
import org.openrewrite.java.JavaParser;
2223
import org.openrewrite.test.RecipeSpec;
2324
import org.openrewrite.test.RewriteTest;
@@ -91,7 +92,35 @@ class Test {
9192
}
9293

9394
@Test
94-
void replacePredicatesAndWithMethodReferences() {
95+
void replacePredicatesAndWithLambdas() {
96+
//language=java
97+
rewriteRun(
98+
java(
99+
"""
100+
import com.google.common.base.Predicate;
101+
import com.google.common.base.Predicates;
102+
103+
class Test {
104+
Predicate<String> isNotNull = s -> s != null;
105+
Predicate<String> isLong = s -> s.length() > 5;
106+
Predicate<String> combined = Predicates.and(isNotNull, isLong);
107+
}
108+
""",
109+
"""
110+
import com.google.common.base.Predicate;
111+
112+
class Test {
113+
Predicate<String> isNotNull = s -> s != null;
114+
Predicate<String> isLong = s -> s.length() > 5;
115+
Predicate<String> combined = isNotNull.and(isLong);
116+
}
117+
"""
118+
)
119+
);
120+
}
121+
122+
@Test
123+
void replacePredicatesAndWithMethodReference() {
95124
//language=java
96125
rewriteRun(
97126
java(
@@ -109,7 +138,7 @@ class Test {
109138
import java.util.Objects;
110139
111140
class Test {
112-
Predicate<String> combined = Objects::nonNull.and(s -> s.length() > 5);
141+
Predicate<String> combined = ((Predicate<String>) Objects::nonNull).and(s -> s.length() > 5);
113142
}
114143
"""
115144
)
@@ -146,4 +175,66 @@ class Test {
146175
)
147176
);
148177
}
178+
179+
@Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/893")
180+
@Test
181+
void replacePredicatesAndWithMoreThanTwoParameters() {
182+
//language=java
183+
rewriteRun(
184+
java(
185+
"""
186+
import com.google.common.base.Predicate;
187+
import com.google.common.base.Predicates;
188+
189+
class Test {
190+
Predicate<String> isNotNull = s -> s != null;
191+
Predicate<String> isNotEmpty = s -> !s.isEmpty();
192+
Predicate<String> containsA = s -> s.contains("A");
193+
Predicate<String> combined = Predicates.and(isNotNull, isNotEmpty, containsA);
194+
}
195+
""",
196+
"""
197+
import com.google.common.base.Predicate;
198+
199+
class Test {
200+
Predicate<String> isNotNull = s -> s != null;
201+
Predicate<String> isNotEmpty = s -> !s.isEmpty();
202+
Predicate<String> containsA = s -> s.contains("A");
203+
Predicate<String> combined = isNotNull.and(isNotEmpty).and(containsA);
204+
}
205+
"""
206+
)
207+
);
208+
}
209+
210+
@Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/893")
211+
@Test
212+
void replacePredicatesOrWithMoreThanTwoParameters() {
213+
//language=java
214+
rewriteRun(
215+
java(
216+
"""
217+
import com.google.common.base.Predicate;
218+
import com.google.common.base.Predicates;
219+
220+
class Test {
221+
Predicate<String> isNotNull = s -> s != null;
222+
Predicate<String> isNotEmpty = s -> !s.isEmpty();
223+
Predicate<String> containsA = s -> s.contains("A");
224+
Predicate<String> combined = Predicates.or(isNotNull, isNotEmpty, containsA);
225+
}
226+
""",
227+
"""
228+
import com.google.common.base.Predicate;
229+
230+
class Test {
231+
Predicate<String> isNotNull = s -> s != null;
232+
Predicate<String> isNotEmpty = s -> !s.isEmpty();
233+
Predicate<String> containsA = s -> s.contains("A");
234+
Predicate<String> combined = isNotNull.or(isNotEmpty).or(containsA);
235+
}
236+
"""
237+
)
238+
);
239+
}
149240
}

0 commit comments

Comments
 (0)