You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2026/10/18 16:03:05 UTC
(tomcat) 15/18: Coerce EL stream predicate results in the match operations
This is an automated email from the ASF dual-hosted git repository.
rmaucher pushed a commit to branch 11.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 0bd5d52b880a5cdffbbde1c9e21fb76352bef775
Author: opencode <re...@apache.org>
AuthorDate: Sun Oct 18 16:29:15 2026 +0200
Coerce EL stream predicate results in the match operations
The anyMatch, allMatch and noneMatch stream operations treated the
result of each predicate evaluation as an already boxed boolean by
casting it. A predicate returning null produced a raw
NullPointerException when the loop next inspected the result, and a
predicate returning any other non-boolean type, such as a number,
produced a ClassCastException. The filter operation, which takes the
same predicate type, instead coerced the result: null and the empty
string meant false, a convertible string was honoured, and anything
else was reported as an ELException. The Jakarta EL specification
types the predicate as a function to boolean and defines a coercion
for producing a boolean from an arbitrary value, which is what the
filter operation applies.
Coerce the predicate results in the three match operations with the
same coercion used by filter, so the predicate-consuming operations
agree on what a predicate result means and invalid results are
reported as conversion errors rather than as unexpected runtime
exceptions. The short-circuit behaviour of the three operations is
unchanged.
Adds tests for a null predicate result and for a non-boolean predicate
result on the three operations. The null result tests report the raw
NullPointerException against the previous implementation.
---
java/org/apache/el/stream/Stream.java | 6 +--
.../apache/el/stream/TestCollectionOperations.java | 59 ++++++++++++++++++++++
2 files changed, 62 insertions(+), 3 deletions(-)
diff --git a/java/org/apache/el/stream/Stream.java b/java/org/apache/el/stream/Stream.java
index 2a0be487e7..f277757e75 100644
--- a/java/org/apache/el/stream/Stream.java
+++ b/java/org/apache/el/stream/Stream.java
@@ -514,7 +514,7 @@ public class Stream {
Boolean match = Boolean.FALSE;
while (!match.booleanValue() && iterator.hasNext()) {
- match = (Boolean) le.invoke(iterator.next());
+ match = ELSupport.coerceToBoolean(null, le.invoke(iterator.next()), true);
}
return new Optional(match);
@@ -535,7 +535,7 @@ public class Stream {
Boolean match = Boolean.TRUE;
while (match.booleanValue() && iterator.hasNext()) {
- match = (Boolean) le.invoke(iterator.next());
+ match = ELSupport.coerceToBoolean(null, le.invoke(iterator.next()), true);
}
return new Optional(match);
@@ -556,7 +556,7 @@ public class Stream {
Boolean match = Boolean.FALSE;
while (!match.booleanValue() && iterator.hasNext()) {
- match = (Boolean) le.invoke(iterator.next());
+ match = ELSupport.coerceToBoolean(null, le.invoke(iterator.next()), true);
}
return new Optional(Boolean.valueOf(!match.booleanValue()));
diff --git a/test/org/apache/el/stream/TestCollectionOperations.java b/test/org/apache/el/stream/TestCollectionOperations.java
index 05c0068596..a0527488ff 100644
--- a/test/org/apache/el/stream/TestCollectionOperations.java
+++ b/test/org/apache/el/stream/TestCollectionOperations.java
@@ -752,6 +752,65 @@ public class TestCollectionOperations extends ELBaseTest {
}
+ @Test(expected=ELException.class)
+ public void testAnyMatch04() {
+ // A predicate that returns a non-boolean must be coerced, producing an
+ // ELException, as for filter()
+ ELProcessor processor = new ELProcessor();
+
+ processor.getValue(
+ "[1,2,3].stream().anyMatch(x->x)",
+ Object.class);
+ }
+
+
+ @Test
+ public void testAnyMatch05() {
+ // A null predicate result is coerced to false, as for filter()
+ ELProcessor processor = new ELProcessor();
+
+ Optional result = (Optional) processor.getValue(
+ "[1,2,3].stream().anyMatch(x->null)",
+ Object.class);
+
+ Assert.assertEquals(Boolean.FALSE, result.get());
+ }
+
+
+ @Test(expected=ELException.class)
+ public void testAllMatch05() {
+ ELProcessor processor = new ELProcessor();
+
+ processor.getValue(
+ "[1,2,3].stream().allMatch(x->x)",
+ Object.class);
+ }
+
+
+ @Test
+ public void testAllMatch06() {
+ ELProcessor processor = new ELProcessor();
+
+ Optional result = (Optional) processor.getValue(
+ "[1,2,3].stream().allMatch(x->null)",
+ Object.class);
+
+ Assert.assertEquals(Boolean.FALSE, result.get());
+ }
+
+
+ @Test
+ public void testNoneMatch05() {
+ ELProcessor processor = new ELProcessor();
+
+ Optional result = (Optional) processor.getValue(
+ "[1,2,3].stream().noneMatch(x->null)",
+ Object.class);
+
+ Assert.assertEquals(Boolean.TRUE, result.get());
+ }
+
+
@Test
public void testFindFirst01() {
ELProcessor processor = new ELProcessor();
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org