This is an automated email from the ASF dual-hosted git repository.

rmaucher pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 24d8b7549a7c46bb3039920beb90a27c25274226
Author: opencode <[email protected]>
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 5e091824d8..a25a8cfdc4 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 d204043fd6..1a37d1ab70 100644
--- a/test/org/apache/el/stream/TestCollectionOperations.java
+++ b/test/org/apache/el/stream/TestCollectionOperations.java
@@ -751,6 +751,65 @@ public class TestCollectionOperations {
     }
 
 
+    @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: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to