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 <ma...@apache.org>
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: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to