This is an automated email from the ASF dual-hosted git repository.
markt-asf pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/10.1.x by this push:
new a2346e914d Review "Coerce EL stream predicate results in the match
operations"
a2346e914d is described below
commit a2346e914d0bda591652d25547ff6f40fcac8976
Author: Mark Thomas <[email protected]>
AuthorDate: Thu Nov 5 16:30:55 2026 +0000
Review "Coerce EL stream predicate results in the match operations"
Additional error handling so ELException is thrown
---
java/org/apache/el/LocalStrings.properties | 1 +
java/org/apache/el/stream/Stream.java | 18 ++-
.../apache/el/stream/TestCollectionOperations.java | 125 +++++++++++++++++++++
3 files changed, 141 insertions(+), 3 deletions(-)
diff --git a/java/org/apache/el/LocalStrings.properties
b/java/org/apache/el/LocalStrings.properties
index 5681814e8f..df37ba0273 100644
--- a/java/org/apache/el/LocalStrings.properties
+++ b/java/org/apache/el/LocalStrings.properties
@@ -61,5 +61,6 @@ error.value.expectedType=Expected type cannot be null
error.value.literal.write=ValueExpression is a literal and not writable: [{0}]
stream.compare.notComparable=Stream elements must implement Comparable
+stream.compare.sortFailed=Stream elements must implement Comparable and be
comparable with each other
stream.optional.empty=It is illegal to call get() on an empty optional
stream.optional.paramNotLambda=The parameter for the method [{0}] should be a
lambda expression
diff --git a/java/org/apache/el/stream/Stream.java
b/java/org/apache/el/stream/Stream.java
index 98dca68cea..d789101640 100644
--- a/java/org/apache/el/stream/Stream.java
+++ b/java/org/apache/el/stream/Stream.java
@@ -186,7 +186,12 @@ public class Stream {
while (iterator.hasNext()) {
list.add(iterator.next());
}
- Collections.sort(list);
+ try {
+ Collections.sort(list);
+ } catch (ClassCastException cce) {
+ // The elements are not Comparable or are not Comparable
with each other
+ throw new
ELException(MessageFactory.get("stream.compare.sortFailed"), cce);
+ }
sorted = list.iterator();
}
};
@@ -604,9 +609,16 @@ public class Stream {
while (iterator.hasNext()) {
Object obj = iterator.next();
if ((obj instanceof Comparable)) {
- if (isMax && ((Comparable) obj).compareTo(result) > 0) {
+ int comparison;
+ try {
+ comparison = ((Comparable) obj).compareTo(result);
+ } catch (ClassCastException cce) {
+ // The elements are Comparable but not with each other
+ throw new ELException(MessageFactory.get("error.compare",
obj, result), cce);
+ }
+ if (isMax && comparison > 0) {
result = (Comparable) obj;
- } else if (!isMax && ((Comparable) obj).compareTo(result) < 0)
{
+ } else if (!isMax && comparison < 0) {
result = (Comparable) obj;
}
} else {
diff --git a/test/org/apache/el/stream/TestCollectionOperations.java
b/test/org/apache/el/stream/TestCollectionOperations.java
index dcfefc5c34..6233fcf7b0 100644
--- a/test/org/apache/el/stream/TestCollectionOperations.java
+++ b/test/org/apache/el/stream/TestCollectionOperations.java
@@ -17,6 +17,7 @@
package org.apache.el.stream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -498,6 +499,130 @@ public class TestCollectionOperations {
}
+ private static boolean hasCause(Throwable t, Class<? extends Throwable>
cause) {
+ while (t != null) {
+ if (cause.isInstance(t)) {
+ return true;
+ }
+ t = t.getCause();
+ }
+ return false;
+ }
+
+
+ @SuppressWarnings("unchecked")
+ private static Stream streamOf(Object... elements) {
+ return new Stream((java.util.Iterator<Object>)
Arrays.asList(elements).iterator());
+ }
+
+
+ /*
+ * The following tests use the Stream directly so the exception is seen
before any wrapping by the expression
+ * evaluation. The failure must be an ELException with the
ClassCastException as the cause.
+ */
+ @Test
+ public void testMaxDirectNotMutuallyComparable() {
+ try {
+ streamOf(Integer.valueOf(1), "a").max();
+ Assert.fail("An ELException was expected");
+ } catch (ELException e) {
+ Assert.assertTrue("Unexpected cause: " + e.getCause(),
e.getCause() instanceof ClassCastException);
+ }
+ }
+
+
+ @Test
+ public void testMinDirectNotMutuallyComparable() {
+ try {
+ streamOf("a", Integer.valueOf(1)).min();
+ Assert.fail("An ELException was expected");
+ } catch (ELException e) {
+ Assert.assertTrue("Unexpected cause: " + e.getCause(),
e.getCause() instanceof ClassCastException);
+ }
+ }
+
+
+ @Test
+ public void testSortedDirectNotMutuallyComparable() {
+ Stream sorted = streamOf(Integer.valueOf(1), "a").sorted();
+ try {
+ sorted.toList();
+ Assert.fail("An ELException was expected");
+ } catch (ELException e) {
+ Assert.assertTrue("Unexpected cause: " + e.getCause(),
e.getCause() instanceof ClassCastException);
+ }
+ }
+
+
+ @Test
+ public void testSortedDirectNotComparable() {
+ Stream sorted = streamOf(new Object(), new Object()).sorted();
+ try {
+ sorted.toList();
+ Assert.fail("An ELException was expected");
+ } catch (ELException e) {
+ Assert.assertTrue("Unexpected cause: " + e.getCause(),
e.getCause() instanceof ClassCastException);
+ }
+ }
+
+
+ @Test
+ public void testMax05() {
+ // The elements are Comparable but not with each other. This must be
reported as an ELException rather than
+ // as the ClassCastException from compareTo()
+ ELProcessor processor = new ELProcessor();
+
+ try {
+ processor.getValue("[1,'a'].stream().max()", Object.class);
+ Assert.fail("An ELException was expected");
+ } catch (ELException e) {
+ Assert.assertTrue("Unexpected cause: " + e, hasCause(e,
ClassCastException.class));
+ }
+ }
+
+
+ @Test
+ public void testMin05() {
+ ELProcessor processor = new ELProcessor();
+
+ try {
+ processor.getValue("['a',1].stream().min()", Object.class);
+ Assert.fail("An ELException was expected");
+ } catch (ELException e) {
+ Assert.assertTrue("Unexpected cause: " + e, hasCause(e,
ClassCastException.class));
+ }
+ }
+
+
+ @Test
+ public void testSorted03() {
+ // Elements that are Comparable but not with each other
+ ELProcessor processor = new ELProcessor();
+
+ try {
+ processor.getValue("[1,'a'].stream().sorted().toList()",
Object.class);
+ Assert.fail("An ELException was expected");
+ } catch (ELException e) {
+ Assert.assertTrue("Unexpected cause: " + e, hasCause(e,
ClassCastException.class));
+ }
+ }
+
+
+ @Test
+ public void testSorted04() {
+ // Elements that are not Comparable at all
+ ELProcessor processor = new ELProcessor();
+ processor.defineBean("beans", beans);
+
+ try {
+ processor.getValue("beans.stream().sorted().toList()",
Object.class);
+ Assert.fail("An ELException was expected");
+ } catch (ELException e) {
+ Assert.assertTrue("Unexpected cause: " + e, hasCause(e,
ClassCastException.class));
+ }
+ }
+
+
@Test
public void testMaxLambda01() {
ELProcessor processor = new ELProcessor();
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]