I have this Java 8 code which works fine:
//Java 8
@Test public void testPredicates(){
Predicate<Integer> p1 = (i) -> true;
Predicate<Integer> p2 = (i) -> true;
Predicate<Integer> p3 = p1.and(p2);
List<Integer> is = new ArrayList<>();
is.add(1);
is.add(2);
assertTrue(is.stream().allMatch(p1.and(p2)));
}
The closest I can get to it in Groovy (2.2) is this:
//Groovy 2.2
@Test
void test(){
Predicate<Integer> p1 = { i -> true}
Predicate<Integer> p2 = {i -> true}
Predicate<Integer> p3 = p2.and(p1)
List<Integer> is = new ArrayList<>()
is.add(1)
is.add(2)
assert(is.stream().allMatch(p1.and(p2)))
}
The Groovy code fails with the following on the line which calls the and
method:
java.lang.ClassCastException: java.lang.Boolean
cannot be cast to java.util.function.Predicate
If I replace the assertion with just assert(is.stream().allMatch(p1))
, then the test completes successfully. The problem is calling the and
method on the predicate.
Inspecting for example p2
in the debugger, I can see it has type OneParameterTest$_test_closure2
. Decompiling the bytecode verifys this.
I have a feeling, although I am not sure, that this relates to implicit closure coersion (see http://groovy.codehaus.org/Groovy+2.2+release+notes).
Is there any way to write Groovy code so that it creates the predicate as a true instance of java.util.function.Predicate
?
In practice, the problem is that the earlier releases of Groovy 2.3 ignore the default methods defined in the interfaces.
From Groovy 2.3 release notes:
Groovy 2.3 doesn’t support the new syntax constructs offered by Java 8 (such as lambdas, method references, default methods in interfaces, etc), but you can very well already use the new APIs offered by JDK 8, and even use Groovy closures in lieu of Java 8 lambdas.
It is fixed (at least for the above case) in 2.3.8 and 2.4 as part of GROOVY-7104
Is there any way to write Groovy code so that it creates the predicate as a true instance of java.util.function.Predicate?
What you are doing there is creating a true instance of Predicate. The problem is the way you are creating them is really only useful for single method interfaces. Predicate defines several methods. There are several ways you could go about this. Maybe the simplest is to take advantage of Groovy's Map to interface support. The code below only accounts for "and" and "test", but you can provide whatever you actually are calling and omit the others.
It is hard to say from your code snippet what you are really trying to accomplish but just to address the specific test you have written, you should be able to do something like this. The test methods are all hardcoded to return true here, just like in your test, but you presumably would have real logic there.
Predicate<Integer> p1 = [test:{ t -> true},
and: { Predicate other -> [test: { t -> true}] as Predicate}] as Predicate
// in your example you are never calling p2.and(...), but
// it is included here for consistency with the one above...
Predicate<Integer> p2 = [test:{ t -> true},
and: { Predicate other -> [test: { t -> true}] as Predicate}] as Predicate
// it isn't clear why you are creating p3, but you can...
Predicate<Integer> p3 = p1.and(p2)
List<Integer> is = new ArrayList<>()
is.add(1)
is.add(2)
assert(is.stream().allMatch(p1.and(p2)))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With