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 <[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 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: [email protected] For additional commands, e-mail: [email protected]
