This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/main by this push:
new ae5bc7c809 Add date support to EL's relational operators
ae5bc7c809 is described below
commit ae5bc7c8091cee77de1cfcc575b81d413de2e79a
Author: Mark Thomas <[email protected]>
AuthorDate: Fri Jul 4 15:00:53 2025 +0100
Add date support to EL's relational operators
---
java/org/apache/el/lang/ELSupport.java | 59 +++++++++++++++++++++++++++++++---
webapps/docs/changelog.xml | 5 +++
2 files changed, 59 insertions(+), 5 deletions(-)
diff --git a/java/org/apache/el/lang/ELSupport.java
b/java/org/apache/el/lang/ELSupport.java
index e9a6ad4ac5..9384ded46b 100644
--- a/java/org/apache/el/lang/ELSupport.java
+++ b/java/org/apache/el/lang/ELSupport.java
@@ -24,7 +24,12 @@ import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.math.BigDecimal;
import java.math.BigInteger;
+import java.sql.Timestamp;
+import java.time.Clock;
+import java.time.Instant;
+import java.time.temporal.TemporalAccessor;
import java.util.Collections;
+import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
@@ -58,6 +63,9 @@ public class ELSupport {
* If either object is a BigDecimal, then coerce both to BigDecimal first.
Similarly for Double(Float), BigInteger,
* and Long(Integer, Char, Short, Byte).
* <p>
+ * If either object is TemporalAccessor, Clock, java.util.Date or
java.sql.Timestamp, coerce both to Instant and
+ * then compare.
+ *
* Otherwise, check that the first object is an instance of Comparable,
and compare against the second object. If
* that is null, return 1, otherwise return the result of comparing
against the second object.
* <p>
@@ -104,6 +112,11 @@ public class ELSupport {
Long l1 = (Long) coerceToNumber(ctx, obj1, Long.class);
return l0.compareTo(l1);
}
+ if (isDateOp(obj0, obj1)) {
+ Instant i0 = coerceToInstant(ctx, obj0);
+ Instant i1 = coerceToInstant(ctx, obj1);
+ return i0.compareTo(i1);
+ }
if (obj0 instanceof String || obj1 instanceof String) {
return coerceToString(ctx, obj0).compareTo(coerceToString(ctx,
obj1));
}
@@ -168,6 +181,10 @@ public class ELSupport {
return obj0.equals(coerceToEnum(ctx, obj1, obj0.getClass()));
} else if (obj1.getClass().isEnum()) {
return obj1.equals(coerceToEnum(ctx, obj0, obj1.getClass()));
+ } else if (isDateOp(obj0, obj1)) {
+ Instant i0 = coerceToInstant(ctx, obj0);
+ Instant i1 = coerceToInstant(ctx, obj1);
+ return i0.equals(i1);
} else if (obj0 instanceof String || obj1 instanceof String) {
int lexCompare = coerceToString(ctx,
obj0).compareTo(coerceToString(ctx, obj1));
return lexCompare == 0;
@@ -475,6 +492,32 @@ public class ELSupport {
};
}
+
+ private static Instant coerceToInstant(final ELContext ctx, final Object
obj) {
+ if (ctx != null) {
+ boolean originalIsPropertyResolved = ctx.isPropertyResolved();
+ try {
+ Instant result = ctx.getELResolver().convertToType(ctx, obj,
Instant.class);
+ if (ctx.isPropertyResolved()) {
+ return result;
+ }
+ } finally {
+ ctx.setPropertyResolved(originalIsPropertyResolved);
+ }
+ }
+
+ return switch (obj) {
+ case null -> null;
+ case TemporalAccessor t -> Instant.from(t);
+ case Clock c -> c.instant();
+ case Date d -> d.toInstant();
+ case String s -> Instant.parse(s);
+ default -> {
+ throw new ELException(MessageFactory.get("error.convert", obj,
obj.getClass().getName(), Instant.class));
+ }
+ };
+ }
+
public static <T> T coerceToType(final ELContext ctx, final Object obj,
final Class<T> type)
throws ELException {
@@ -621,21 +664,27 @@ public class ELSupport {
public static boolean isBigDecimalOp(final Object obj0, final Object obj1)
{
- return (obj0 instanceof BigDecimal || obj1 instanceof BigDecimal);
+ return obj0 instanceof BigDecimal || obj1 instanceof BigDecimal;
}
public static boolean isBigIntegerOp(final Object obj0, final Object obj1)
{
- return (obj0 instanceof BigInteger || obj1 instanceof BigInteger);
+ return obj0 instanceof BigInteger || obj1 instanceof BigInteger;
}
public static boolean isDoubleOp(final Object obj0, final Object obj1) {
- return (obj0 instanceof Double || obj1 instanceof Double || obj0
instanceof Float || obj1 instanceof Float);
+ return obj0 instanceof Double || obj1 instanceof Double || obj0
instanceof Float || obj1 instanceof Float;
}
public static boolean isLongOp(final Object obj0, final Object obj1) {
- return (obj0 instanceof Long || obj1 instanceof Long || obj0
instanceof Integer || obj1 instanceof Integer ||
+ return obj0 instanceof Long || obj1 instanceof Long || obj0 instanceof
Integer || obj1 instanceof Integer ||
obj0 instanceof Character || obj1 instanceof Character || obj0
instanceof Short ||
- obj1 instanceof Short || obj0 instanceof Byte || obj1
instanceof Byte);
+ obj1 instanceof Short || obj0 instanceof Byte || obj1
instanceof Byte;
+ }
+
+ public static boolean isDateOp(final Object obj0, Object obj1) {
+ return obj0 instanceof TemporalAccessor || obj1 instanceof
TemporalAccessor || obj0 instanceof Clock ||
+ obj1 instanceof Clock ||obj0 instanceof Date || obj1
instanceof Date ||obj0 instanceof Timestamp ||
+ obj1 instanceof Timestamp;
}
public static boolean isStringFloat(final String str) {
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index c40b183d38..de4cee0e3f 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -208,6 +208,11 @@
marker class,
<code>jakarta.el.ELResolver.StandaloneIdentifierMarker</code>. (markt)
</scode>
+ <add>
+ Extend the support for relational operators to include
+ <code>TemporalAccessor</code>, <code>Clock</code> and
<code>Date</code>.
+ (markt)
+ </add>
<!-- Entries for backport and removal before 12.0.0-M1 below this line
-->
</changelog>
</subsection>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]