Skip to content

Commit 6f906af

Browse files
timtebeeklredor
andauthored
Only convert Guava Predicate when not used as method argument (#902)
* Only convert Guava Predicate when not used as method argument * Add more tests (#904) In the Sirius codebase, I had identified other errors of the same kind for which I hadn’t yet created an issue. I’ve added the corresponding cases to the NoGuavaPredicateTest tests. * Do convert `Predicates.not` to `java.util.function.Predicate.not` * Restore original test * Fix formatting --------- Co-authored-by: Laurent Redor <[email protected]>
1 parent fd556ee commit 6f906af

File tree

4 files changed

+381
-4
lines changed

4 files changed

+381
-4
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
* <p>
4+
* Licensed under the Moderne Source Available License (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://docs.moderne.io/licensing/moderne-source-available-license
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.openrewrite.java.migrate.guava;
17+
18+
import org.openrewrite.ExecutionContext;
19+
import org.openrewrite.Preconditions;
20+
import org.openrewrite.Recipe;
21+
import org.openrewrite.TreeVisitor;
22+
import org.openrewrite.java.ChangeType;
23+
import org.openrewrite.java.JavaIsoVisitor;
24+
import org.openrewrite.java.MethodMatcher;
25+
import org.openrewrite.java.tree.J;
26+
import org.openrewrite.java.tree.JavaSourceFile;
27+
import org.openrewrite.java.tree.JavaType;
28+
import org.openrewrite.marker.SearchResult;
29+
30+
public class NoGuavaPredicate extends Recipe {
31+
@Override
32+
public String getDisplayName() {
33+
return "Change Guava's `Predicate` into `java.util.function.Predicate` where possible";
34+
}
35+
36+
@Override
37+
public String getDescription() {
38+
return "Change the type only where no methods are used that explicitly require a Guava `Predicate`.";
39+
}
40+
41+
@Override
42+
public TreeVisitor<?, ExecutionContext> getVisitor() {
43+
return Preconditions.check(
44+
Preconditions.not(new UsesPredicateMethod<>()),
45+
new ChangeType(
46+
"com.google.common.base.Predicate",
47+
"java.util.function.Predicate",
48+
false)
49+
.getVisitor()
50+
);
51+
}
52+
53+
private static class UsesPredicateMethod<P> extends JavaIsoVisitor<P> {
54+
private static final MethodMatcher PREDICATE_METHOD_MATCHER = new MethodMatcher("*..* *(.., com.google.common.base.Predicate)");
55+
private static final MethodMatcher NOT_MATCHER = new MethodMatcher("*..* not(com.google.common.base.Predicate)");
56+
57+
@Override
58+
public J preVisit(J tree, P p) {
59+
stopAfterPreVisit();
60+
if (tree instanceof JavaSourceFile) {
61+
JavaSourceFile cu = (JavaSourceFile) tree;
62+
for (JavaType.Method type : cu.getTypesInUse().getUsedMethods()) {
63+
if (PREDICATE_METHOD_MATCHER.matches(type) &&
64+
// Make an exception for `not` methods; those can be safely converted
65+
!NOT_MATCHER.matches(type)) {
66+
return SearchResult.found(cu);
67+
}
68+
}
69+
}
70+
return tree;
71+
}
72+
}
73+
}

src/main/resources/META-INF/rewrite/no-guava.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,7 @@ recipeList:
195195
methodPattern: com.google.common.base.Predicate apply(..)
196196
newMethodName: test
197197
matchOverrides: true
198-
- org.openrewrite.java.ChangeType:
199-
oldFullyQualifiedTypeName: com.google.common.base.Predicate
200-
newFullyQualifiedTypeName: java.util.function.Predicate
198+
- org.openrewrite.java.migrate.guava.NoGuavaPredicate
201199

202200
---
203201
type: specs.openrewrite.org/v1beta/recipe
Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
* <p>
4+
* Licensed under the Moderne Source Available License (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://docs.moderne.io/licensing/moderne-source-available-license
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.openrewrite.java.migrate.guava;
17+
18+
import org.junit.jupiter.api.Test;
19+
import org.openrewrite.DocumentExample;
20+
import org.openrewrite.InMemoryExecutionContext;
21+
import org.openrewrite.Issue;
22+
import org.openrewrite.java.JavaParser;
23+
import org.openrewrite.test.RecipeSpec;
24+
import org.openrewrite.test.RewriteTest;
25+
26+
import static org.openrewrite.java.Assertions.java;
27+
28+
class NoGuavaPredicateTest implements RewriteTest {
29+
@Override
30+
public void defaults(RecipeSpec spec) {
31+
spec
32+
.recipe(new NoGuavaPredicate())
33+
.parser(JavaParser.fromJavaVersion().classpathFromResources(new InMemoryExecutionContext(), "guava"));
34+
}
35+
36+
@DocumentExample
37+
@Test
38+
void changeGuavaPredicateToJavaUtilPredicate() {
39+
rewriteRun(
40+
//language=java
41+
java(
42+
"""
43+
import com.google.common.base.Predicate;
44+
45+
class Test {
46+
Predicate<String> predicate = input -> input != null && !input.isEmpty();
47+
}
48+
""",
49+
"""
50+
import java.util.function.Predicate;
51+
52+
class Test {
53+
Predicate<String> predicate = input -> input != null && !input.isEmpty();
54+
}
55+
"""
56+
)
57+
);
58+
}
59+
60+
@Test
61+
void changeWhenMethodOnlyReturnsGuavaPredicate() {
62+
// Recipe only blocks when Predicate is used as a parameter, not return type
63+
rewriteRun(
64+
//language=java
65+
java(
66+
"""
67+
import com.google.common.base.Predicate;
68+
69+
class Test {
70+
Predicate<String> predicate = input -> input != null;
71+
72+
public Predicate<String> createPredicate() {
73+
return s -> s.isEmpty();
74+
}
75+
}
76+
""",
77+
"""
78+
import java.util.function.Predicate;
79+
80+
class Test {
81+
Predicate<String> predicate = input -> input != null;
82+
83+
public Predicate<String> createPredicate() {
84+
return s -> s.isEmpty();
85+
}
86+
}
87+
"""
88+
)
89+
);
90+
}
91+
92+
@Test
93+
void changePredicatesNot() {
94+
rewriteRun(
95+
spec -> spec.recipeFromResource(
96+
"/META-INF/rewrite/no-guava.yml",
97+
"org.openrewrite.java.migrate.guava.PreferJavaUtilPredicate"),
98+
//language=java
99+
java(
100+
"""
101+
import com.google.common.base.Predicate;
102+
import com.google.common.base.Predicates;
103+
104+
class A {
105+
Predicate<String> notEmptyPredicate() {
106+
Predicate<String> isEmpty = String::isEmpty;
107+
return Predicates.not(isEmpty);
108+
}
109+
}
110+
""",
111+
"""
112+
import java.util.function.Predicate;
113+
114+
class A {
115+
Predicate<String> notEmptyPredicate() {
116+
Predicate<String> isEmpty = String::isEmpty;
117+
return Predicate.not(isEmpty);
118+
}
119+
}
120+
"""
121+
)
122+
);
123+
}
124+
125+
@Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/897")
126+
@Test
127+
void doNotChangeWhenUsingSetsFilter() {
128+
// Sets.filter requires Guava Predicate as last parameter
129+
rewriteRun(
130+
//language=java
131+
java(
132+
"""
133+
import com.google.common.base.Predicate;
134+
import com.google.common.collect.Sets;
135+
import java.util.Set;
136+
137+
class Test {
138+
Predicate<String> notEmpty = s -> !s.isEmpty();
139+
140+
public Set<String> filterSet(Set<String> input) {
141+
return Sets.filter(input, notEmpty);
142+
}
143+
}
144+
"""
145+
)
146+
);
147+
}
148+
149+
@Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/883")
150+
@Test
151+
void doNotChangeWhenUsingIterablesFilter() {
152+
// Iterables.filter requires Guava Predicate as last parameter
153+
rewriteRun(
154+
//language=java
155+
java(
156+
"""
157+
import com.google.common.base.Predicate;
158+
import com.google.common.collect.Iterables;
159+
import java.util.List;
160+
161+
class Test {
162+
Predicate<Integer> isPositive = n -> n > 0;
163+
164+
public Iterable<Integer> filterPositive(List<Integer> numbers) {
165+
return Iterables.filter(numbers, isPositive);
166+
}
167+
}
168+
"""
169+
)
170+
);
171+
}
172+
173+
@Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/899")
174+
@Test
175+
void doNotChangeWhenUsingCollectionsFilter() {
176+
// Collections2.filter requires Guava Predicate as last parameter
177+
rewriteRun(
178+
//language=java
179+
java(
180+
"""
181+
import com.google.common.base.Predicate;
182+
import com.google.common.collect.Collections2;
183+
import java.util.Collection;
184+
185+
class Test {
186+
Predicate<String> notEmpty = s -> !s.isEmpty();
187+
188+
public Collection<String> filterCollection(Collection<String> input) {
189+
return Collections2.filter(input, notEmpty);
190+
}
191+
}
192+
"""
193+
)
194+
);
195+
}
196+
197+
@Test
198+
void doNotChangeWhenUsingIteratorsFilter() {
199+
// Iterators.filter requires Guava Predicate as last parameter
200+
rewriteRun(
201+
//language=java
202+
java(
203+
"""
204+
import com.google.common.base.Predicate;
205+
import com.google.common.collect.Iterators;
206+
207+
import java.util.Iterator;
208+
209+
class Test {
210+
Predicate<Integer> isPositive = n -> n > 0;
211+
212+
public Iterator<Integer> filterPositive(Iterator<Integer> numbers) {
213+
return Iterators.filter(numbers, isPositive);
214+
}
215+
}
216+
"""
217+
)
218+
);
219+
}
220+
221+
@Test
222+
void doNotChangeWhenUsingIterablesAny() {
223+
// Iterables.any requires Guava Predicate as last parameter
224+
rewriteRun(
225+
//language=java
226+
java(
227+
"""
228+
import com.google.common.base.Predicate;
229+
import com.google.common.collect.Iterables;
230+
import java.util.List;
231+
232+
class Test {
233+
public boolean any(List<Integer> input, Predicate<Integer> aPredicate) {
234+
return Iterables.any(input, aPredicate);
235+
}
236+
}
237+
"""
238+
)
239+
);
240+
}
241+
242+
@Test
243+
void doNotChangeWhenUsingMapsFilterEntries() {
244+
// Maps.filterEntries requires Guava Predicate as last parameter
245+
rewriteRun(
246+
//language=java
247+
java(
248+
"""
249+
import com.google.common.base.Predicate;
250+
import com.google.common.collect.Maps;
251+
import java.util.Map;
252+
253+
class Test {
254+
public Map<String, String> filterMap(Map<String, String> input, Predicate<Map.Entry<String,String>> aPredicate) {
255+
return Maps.filterEntries(input, aPredicate);
256+
}
257+
}
258+
"""
259+
)
260+
);
261+
}
262+
263+
@Test
264+
void doNotChangeWhenUsingMapsFilterValues() {
265+
// Maps.filterValues requires Guava Predicate as last parameter
266+
rewriteRun(
267+
//language=java
268+
java(
269+
"""
270+
import com.google.common.base.Predicate;
271+
import com.google.common.collect.Maps;
272+
import java.util.Map;
273+
274+
class Test {
275+
public Map<String, String> filterMap(Map<String, String> input, Predicate<String> aPredicate) {
276+
return Maps.filterValues(input, aPredicate);
277+
}
278+
}
279+
"""
280+
)
281+
);
282+
}
283+
284+
@Test
285+
void doNotChangeWhenUsingMapsFilterKeys() {
286+
// Maps.filterKeys requires Guava Predicate as last parameter
287+
rewriteRun(
288+
//language=java
289+
java(
290+
"""
291+
import com.google.common.base.Predicate;
292+
import com.google.common.collect.Maps;
293+
import java.util.Map;
294+
295+
class Test {
296+
public Map<String, String> filterMap(Map<String, String> input, Predicate<String> aPredicate) {
297+
return Maps.filterKeys(input, aPredicate);
298+
}
299+
}
300+
"""
301+
)
302+
);
303+
}
304+
}

0 commit comments

Comments
 (0)