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