You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by he...@apache.org on 2022/11/26 15:33:27 UTC

[commons-jexl] branch master updated: JEXL-384: revisit control implementation to better preserve previous JexlArithmetic (user) derived classes;

This is an automated email from the ASF dual-hosted git repository.

henrib pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-jexl.git


The following commit(s) were added to refs/heads/master by this push:
     new 9681adbb JEXL-384: revisit control implementation to better preserve previous JexlArithmetic (user) derived classes;
     new d5d9dbe1 Merge remote-tracking branch 'origin/master'
9681adbb is described below

commit 9681adbbd14362e751a21658f877f8aa919fed6e
Author: henrib <he...@apache.org>
AuthorDate: Sat Nov 26 16:33:19 2022 +0100

    JEXL-384: revisit control implementation to better preserve previous JexlArithmetic (user) derived classes;
---
 .../org/apache/commons/jexl3/JexlArithmetic.java   | 251 +++++++++++----------
 .../commons/jexl3/jexl342/OptionalArithmetic.java  |   4 +
 2 files changed, 135 insertions(+), 120 deletions(-)

diff --git a/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java b/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java
index 21bd8595..1be73232 100644
--- a/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java
+++ b/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java
@@ -365,91 +365,12 @@ public class JexlArithmetic {
     }
 
     /**
-     * Coerce to a primitive boolean.
-     * <p>Double.NaN, null, "false" and empty string coerce to false.</p>
-     *
-     * @param val value to coerce
-     * @return the boolean value if coercion is possible, true if value was not null.
-     */
-    public boolean toBoolean(final Object val) {
-        return toBoolean(strict, val);
-    }
-
-    /**
-     * Coerce to a primitive int.
-     * <p>Double.NaN, null and empty string coerce to zero.</p>
-     * <p>Boolean false is 0, true is 1.</p>
-     *
-     * @param val value to coerce
-     * @return the value coerced to int
-     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
+     * Checks if an operand is considered null.
+     * @apram val the operand
+     * @erturn true if operand is considered null
      */
-    public int toInteger(final Object val) {
-        return toInteger(strict, val);
-    }
-
-    /**
-     * Coerce to a primitive long.
-     * <p>Double.NaN, null and empty string coerce to zero.</p>
-     * <p>Boolean false is 0, true is 1.</p>
-     *
-     * @param val value to coerce
-     * @return the value coerced to long
-     * @throws ArithmeticException if value is null and mode is strict or if coercion is not possible
-     */
-    public long toLong(final Object val) {
-        return toLong(strict, val);
-    }
-
-    /**
-     * Coerce to a BigInteger.
-     * <p>Double.NaN, null and empty string coerce to zero.</p>
-     * <p>Boolean false is 0, true is 1.</p>
-     *
-     * @param val the object to be coerced.
-     * @return a BigDecimal
-     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
-     */
-    public BigInteger toBigInteger(final Object val) {
-        return toBigInteger(strict, val);
-    }
-
-    /**
-     * Coerce to a primitive double.
-     * <p>Double.NaN, null and empty string coerce to zero.</p>
-     * <p>Boolean false is 0, true is 1.</p>
-     *
-     * @param val value to coerce.
-     * @return The double coerced value.
-     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
-     */
-    public double toDouble(final Object val) {
-        return toDouble(strict, val);
-    }
-
-    /**
-     * Coerce to a BigDecimal.
-     * <p>Double.NaN, null and empty string coerce to zero.</p>
-     * <p>Boolean false is 0, true is 1.</p>
-     *
-     * @param val the object to be coerced.
-     * @return a BigDecimal.
-     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
-     */
-    public BigDecimal toBigDecimal(final Object val) {
-        return toBigDecimal(strict, val);
-    }
-
-    /**
-     * Coerce to a string.
-     * <p>Double.NaN coerce to the empty string.</p>
-     *
-     * @param val value to coerce.
-     * @return The String coerced value.
-     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
-     */
-    public String toString(final Object val) {
-        return toString(strict, val);
+    protected boolean isNullOperand(Object value) {
+        return value == null;
     }
 
     /**
@@ -460,12 +381,16 @@ public class JexlArithmetic {
      * {@link #toBigDecimal(boolean, Object)}) when they encounter a null argument.</p>
      *
      * @param strictCast whether strict cast is required
+     * @param defaultValue the default value to return, if not strict
+     * @eeturn the default value is strict is false
      * @throws JexlArithmetic.NullOperand if strict-cast
+     * @since 3.3
      */
-    protected void controlNullOperand(boolean strictCast) {
+    protected <T> T controlNullOperand(boolean strictCast, T defaultValue) {
         if (strictCast) {
             throw new NullOperand();
         }
+        return defaultValue;
     }
 
     /**
@@ -473,6 +398,7 @@ public class JexlArithmetic {
      * @param strictCast whether strict-cast is required
      * @return Integer(0) if lenient
      * @throws  JexlArithmetic.NullOperand if strict-cast
+     * @since 3.3
      */
     protected Object controlNullNullOperands(boolean strictCast) {
         if (strictCast ) {
@@ -490,10 +416,17 @@ public class JexlArithmetic {
      * @return the boolean value if coercion is possible, true if value was not null.
      */
     protected boolean toBoolean(final boolean strict, final Object val) {
-        if (val == null) {
-            controlNullOperand(strict);
-            return false;
-        }
+        return isNullOperand(val)? controlNullOperand(strict, false) : toBoolean(val);
+    }
+
+    /**
+     * Coerce to a primitive boolean.
+     * <p>Double.NaN, null, "false" and empty string coerce to false.</p>
+     *
+     * @param val value to coerce
+     * @return the boolean value if coercion is possible, true if value was not null.
+     */
+    public boolean toBoolean(final Object val) {
         if (val instanceof Boolean) {
             return ((Boolean) val);
         }
@@ -508,6 +441,9 @@ public class JexlArithmetic {
             final String strval = val.toString();
             return !strval.isEmpty() && !"false".equals(strval);
         }
+        if (val == null) {
+            return controlNullOperand(strict, false);
+        }
         // non-null value is true
         return true;
     }
@@ -521,12 +457,22 @@ public class JexlArithmetic {
      * @param val value to coerce
      * @return the value coerced to int
      * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
+     * @since 3.3
      */
     protected int toInteger(final boolean strict, final Object val) {
-        if (val == null) {
-            controlNullOperand(strict);
-            return 0;
-        }
+        return isNullOperand(val)? controlNullOperand(strict, 0) : toInteger(val);
+    }
+
+    /**
+     * Coerce to a primitive int.
+     * <p>Double.NaN, null and empty string coerce to zero.</p>
+     * <p>Boolean false is 0, true is 1.</p>
+     *
+     * @param val value to coerce
+     * @return the value coerced to int
+     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
+     */
+    public int toInteger(final Object val) {
         if (val instanceof Double) {
             final double dval = (Double) val;
             return Double.isNaN(dval)? 0 : (int) dval;
@@ -546,6 +492,9 @@ public class JexlArithmetic {
         if (val instanceof Character) {
             return ((Character) val);
         }
+        if (val == null) {
+            return controlNullOperand(strict, 0);
+        }
         throw new ArithmeticException("Integer coercion: "
                 + val.getClass().getName() + ":(" + val + ")");
     }
@@ -559,12 +508,22 @@ public class JexlArithmetic {
      * @param val value to coerce
      * @return the value coerced to long
      * @throws ArithmeticException if value is null and mode is strict or if coercion is not possible
+     * @since 3.3
      */
     protected long toLong(final boolean strict, final Object val) {
-        if (val == null) {
-            controlNullOperand(strict);
-            return 0L;
-        }
+        return isNullOperand(val)? controlNullOperand(strict, 0L) : toLong(val);
+    }
+
+    /**
+     * Coerce to a primitive long.
+     * <p>Double.NaN, null and empty string coerce to zero.</p>
+     * <p>Boolean false is 0, true is 1.</p>
+     *
+     * @param val value to coerce
+     * @return the value coerced to long
+     * @throws ArithmeticException if value is null and mode is strict or if coercion is not possible
+     */
+    public long toLong(final Object val) {
         if (val instanceof Double) {
             final double dval = (Double) val;
             return Double.isNaN(dval)? 0L : (long) dval;
@@ -584,6 +543,9 @@ public class JexlArithmetic {
         if (val instanceof Character) {
             return ((Character) val);
         }
+        if (val == null) {
+            return controlNullOperand(strict, 0L);
+        }
         throw new ArithmeticException("Long coercion: "
                 + val.getClass().getName() + ":(" + val + ")");
     }
@@ -597,12 +559,22 @@ public class JexlArithmetic {
      * @param val the object to be coerced.
      * @return a BigDecimal
      * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
+     * @since 3.3
      */
     protected BigInteger toBigInteger(final boolean strict, final Object val) {
-        if (val == null) {
-            controlNullOperand(strict);
-            return BigInteger.ZERO;
-        }
+        return isNullOperand(val)? controlNullOperand(strict, BigInteger.ZERO) : toBigInteger(val);
+    }
+
+    /**
+     * Coerce to a BigInteger.
+     * <p>Double.NaN, null and empty string coerce to zero.</p>
+     * <p>Boolean false is 0, true is 1.</p>
+     *
+     * @param val the object to be coerced.
+     * @return a BigDecimal
+     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
+     */
+    public BigInteger toBigInteger(final Object val) {
         if (val instanceof BigInteger) {
             return (BigInteger) val;
         }
@@ -632,6 +604,9 @@ public class JexlArithmetic {
             final int i = ((Character) val);
             return BigInteger.valueOf(i);
         }
+        if (val == null) {
+            return controlNullOperand(strict, BigInteger.ZERO);
+        }
         throw new ArithmeticException("BigInteger coercion: "
                 + val.getClass().getName() + ":(" + val + ")");
     }
@@ -645,15 +620,25 @@ public class JexlArithmetic {
      * @param val the object to be coerced.
      * @return a BigDecimal.
      * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
+     * @since 3.3
      */
     protected BigDecimal toBigDecimal(final boolean strict, final Object val) {
+        return isNullOperand(val)? controlNullOperand(strict, BigDecimal.ZERO) : toBigDecimal(val);
+    }
+
+    /**
+     * Coerce to a BigDecimal.
+     * <p>Double.NaN, null and empty string coerce to zero.</p>
+     * <p>Boolean false is 0, true is 1.</p>
+     *
+     * @param val the object to be coerced.
+     * @return a BigDecimal.
+     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
+     */
+    public BigDecimal toBigDecimal(final Object val) {
         if (val instanceof BigDecimal) {
             return roundBigDecimal((BigDecimal) val);
         }
-        if (val == null) {
-            controlNullOperand(strict);
-            return BigDecimal.ZERO;
-        }
         if (val instanceof Double) {
             if (Double.isNaN(((Double) val))) {
                 return BigDecimal.ZERO;
@@ -680,6 +665,9 @@ public class JexlArithmetic {
             final int i = ((Character) val);
             return new BigDecimal(i);
         }
+        if (val == null) {
+            return controlNullOperand(strict, BigDecimal.ZERO);
+        }
         throw new ArithmeticException("BigDecimal coercion: "
                 + val.getClass().getName() + ":(" + val + ")");
     }
@@ -693,12 +681,22 @@ public class JexlArithmetic {
      * @param val value to coerce.
      * @return The double coerced value.
      * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
+     * @since 3.3
      */
     protected double toDouble(final boolean strict, final Object val) {
-        if (val == null) {
-            controlNullOperand(strict);
-            return 0;
-        }
+        return isNullOperand(val)? controlNullOperand(strict, 0.d) : toDouble(val);
+    }
+
+    /**
+     * Coerce to a primitive double.
+     * <p>Double.NaN, null and empty string coerce to zero.</p>
+     * <p>Boolean false is 0, true is 1.</p>
+     *
+     * @param val value to coerce.
+     * @return The double coerced value.
+     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
+     */
+    public double toDouble(final Object val) {
         if (val instanceof Double) {
             return ((Double) val);
         }
@@ -719,6 +717,9 @@ public class JexlArithmetic {
         if (val instanceof Character) {
             return ((Character) val);
         }
+        if (val == null) {
+            return controlNullOperand(strict, 0.d);
+        }
         throw new ArithmeticException("Double coercion: "
                 + val.getClass().getName() + ":(" + val + ")");
     }
@@ -731,21 +732,31 @@ public class JexlArithmetic {
      * @param val value to coerce.
      * @return The String coerced value.
      * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
+     * @since 3.3
      */
     protected String toString(final boolean strict, final Object val) {
-        if (val == null) {
-            controlNullOperand(strict);
-            return "";
-        }
-        if (!(val instanceof Double)) {
-            return val.toString();
-        }
-        final Double dval = (Double) val;
-        if (Double.isNaN(dval)) {
-            return "";
+        return isNullOperand(val)? controlNullOperand(strict, "") : toString(val);
+    }
+
+    /**
+     * Coerce to a string.
+     * <p>Double.NaN coerce to the empty string.</p>
+     *
+     * @param val value to coerce.
+     * @return The String coerced value.
+     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible
+     */
+    public String toString(final Object val) {
+        if (val instanceof Double) {
+            final Double dval = (Double) val;
+            if (Double.isNaN(dval)) {
+                return "";
+            }
+            return dval.toString();
         }
-        return dval.toString();
+        return val == null? controlNullOperand(strict, "") : val.toString();
     }
+
     /**
      * Checks whether this JexlArithmetic instance
      * strictly considers null as an error when used as operand unexpectedly.
diff --git a/src/test/java/org/apache/commons/jexl3/jexl342/OptionalArithmetic.java b/src/test/java/org/apache/commons/jexl3/jexl342/OptionalArithmetic.java
index 9bce162c..a3856cdb 100644
--- a/src/test/java/org/apache/commons/jexl3/jexl342/OptionalArithmetic.java
+++ b/src/test/java/org/apache/commons/jexl3/jexl342/OptionalArithmetic.java
@@ -57,6 +57,10 @@ public class OptionalArithmetic extends JexlArithmetic {
     public Object controlReturn(Object returned) {
         return star(returned);
     }
+    @Override
+    protected boolean isNullOperand(Object val) {
+        return super.isNullOperand(star(val));
+    }
 
     @Override
     public boolean toBoolean(final Object val) {