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 2016/02/23 19:01:36 UTC

svn commit: r1731915 - in /commons/proper/jexl/trunk/src: main/java/org/apache/commons/jexl3/JexlArithmetic.java test/java/org/apache/commons/jexl3/ArithmeticTest.java

Author: henrib
Date: Tue Feb 23 18:01:36 2016
New Revision: 1731915

URL: http://svn.apache.org/viewvc?rev=1731915&view=rev
Log:
JEXL:
Fixing JEXL-188 using more information from regexp (groups)

Modified:
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java?rev=1731915&r1=1731914&r2=1731915&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java Tue Feb 23 18:01:36 2016
@@ -25,13 +25,14 @@ import java.math.BigInteger;
 import java.math.MathContext;
 import java.util.Collection;
 import java.util.Map;
+import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 /**
  * Perform arithmetic, implements JexlOperator methods.
- * 
+ *
  * <p>This is the class to derive to implement new operator behaviors.</p>
- * 
+ *
  * <p>The 5 base arithmetic operators (+, - , *, /, %) follow the same evaluation rules regarding their arguments.</p>
  * <ol>
  *   <li>If both are null, result is 0</li>
@@ -45,9 +46,9 @@ import java.util.regex.Pattern;
  *     </ol>
  *   </li>
  * </ol>
- * 
+ *
  * Note that the only exception thrown by JexlArithmetic is and must be ArithmeticException.
- * 
+ *
  * @see JexlOperator
  * @since 2.0
  */
@@ -82,7 +83,7 @@ public class JexlArithmetic {
 
     /**
      * Creates a JexlArithmetic.
-     * 
+     *
      * @param astrict whether this arithmetic is strict or lenient
      */
     public JexlArithmetic(boolean astrict) {
@@ -91,7 +92,7 @@ public class JexlArithmetic {
 
     /**
      * Creates a JexlArithmetic.
-     * 
+     *
      * @param astrict     whether this arithmetic is lenient or strict
      * @param bigdContext the math context instance to use for +,-,/,*,% operations on big decimals.
      * @param bigdScale   the scale used for big decimals.
@@ -104,7 +105,7 @@ public class JexlArithmetic {
 
     /**
      * Apply options to this arithmetic which eventually may create another instance.
-     * 
+     *
      * @param options the {@link JexlEngine.Options} to use
      * @return an arithmetic with those options set
      */
@@ -136,7 +137,7 @@ public class JexlArithmetic {
     public interface Uberspect {
         /**
          * Checks whether this uberspect has overloads for a given operator.
-         * 
+         *
          * @param operator the operator to check
          * @return true if an overload exists, false otherwise
          */
@@ -144,7 +145,7 @@ public class JexlArithmetic {
 
         /**
          * Gets the most specific method for an operator.
-         * 
+         *
          * @param operator the operator
          * @param arg      the arguments
          * @return the most specific method or null if no specific override could be found
@@ -154,9 +155,9 @@ public class JexlArithmetic {
 
     /**
      * Helper interface used when creating an array literal.
-     * 
+     *
      * <p>The default implementation creates an array and attempts to type it strictly.</p>
-     * 
+     *
      * <ul>
      *   <li>If all objects are of the same type, the array returned will be an array of that same type</li>
      *   <li>If all objects are Numbers, the array returned will be an array of Numbers</li>
@@ -168,14 +169,14 @@ public class JexlArithmetic {
 
         /**
          * Adds a literal to the array.
-         * 
+         *
          * @param value the item to add
          */
         void add(Object value);
 
         /**
          * Creates the actual "array" instance.
-         * 
+         *
          * @param extended true when the last argument is ', ...'
          * @return the array
          */
@@ -184,7 +185,7 @@ public class JexlArithmetic {
 
     /**
      * Called by the interpreter when evaluating a literal array.
-     * 
+     *
      * @param size the number of elements in the array
      * @return the array builder
      */
@@ -199,14 +200,14 @@ public class JexlArithmetic {
     public interface SetBuilder {
         /**
          * Adds a literal to the set.
-         * 
+         *
          * @param value the item to add
          */
         void add(Object value);
 
         /**
          * Creates the actual "set" instance.
-         * 
+         *
          * @return the set
          */
         Object create();
@@ -214,7 +215,7 @@ public class JexlArithmetic {
 
     /**
      * Called by the interpreter when evaluating a literal set.
-     * 
+     *
      * @param size the number of elements in the set
      * @return the array builder
      */
@@ -229,7 +230,7 @@ public class JexlArithmetic {
     public interface MapBuilder {
         /**
          * Adds a new entry to the map.
-         * 
+         *
          * @param key   the map entry key
          * @param value the map entry value
          */
@@ -237,7 +238,7 @@ public class JexlArithmetic {
 
         /**
          * Creates the actual "map" instance.
-         * 
+         *
          * @return the map
          */
         Object create();
@@ -245,7 +246,7 @@ public class JexlArithmetic {
 
     /**
      * Called by the interpreter when evaluating a literal map.
-     * 
+     *
      * @param size the number of elements in the map
      * @return the map builder
      */
@@ -256,7 +257,7 @@ public class JexlArithmetic {
     /**
      * Creates a literal range.
      * <p>The default implementation only accepts integers and longs.</p>
-     * 
+     *
      * @param from the included lower bound value (null if none)
      * @param to   the included upper bound value (null if none)
      * @return the range as an iterable
@@ -276,7 +277,7 @@ public class JexlArithmetic {
     /**
      * Checks whether this JexlArithmetic instance
      * strictly considers null as an error when used as operand unexpectedly.
-     * 
+     *
      * @return true if strict, false if lenient
      */
     public boolean isStrict() {
@@ -285,7 +286,7 @@ public class JexlArithmetic {
 
     /**
      * The MathContext instance used for +,-,/,*,% operations on big decimals.
-     * 
+     *
      * @return the math context
      */
     public MathContext getMathContext() {
@@ -294,7 +295,7 @@ public class JexlArithmetic {
 
     /**
      * The BigDecimal scale used for comparison and coericion operations.
-     * 
+     *
      * @return the scale
      */
     public int getMathScale() {
@@ -303,7 +304,7 @@ public class JexlArithmetic {
 
     /**
      * Ensure a big decimal is rounded by this arithmetic scale and rounding mode.
-     * 
+     *
      * @param number the big decimal to round
      * @return the rounded big decimal
      */
@@ -318,7 +319,7 @@ public class JexlArithmetic {
 
     /**
      * The result of +,/,-,*,% when both operands are null.
-     * 
+     *
      * @return Integer(0) if lenient
      * @throws ArithmeticException if strict
      */
@@ -331,7 +332,7 @@ public class JexlArithmetic {
 
     /**
      * Throw a NPE if arithmetic is strict.
-     * 
+     *
      * @throws ArithmeticException if strict
      */
     protected void controlNullOperand() {
@@ -342,8 +343,11 @@ public class JexlArithmetic {
 
     /**
      * The float regular expression pattern.
+     * <p>
+     * The decimal and exponent parts are optional and captured allowing to determine if the number is a real
+     * by checking whether one of these 2 capturing groups is not empty.
      */
-    public static final Pattern FLOAT_PATTERN = Pattern.compile("^[+-]?\\d*(\\.\\d*)?([eE]?[+-]?\\d*)?$");
+    public static final Pattern FLOAT_PATTERN = Pattern.compile("^[+-]?\\d*(\\.\\d*)?([eE][+-]?\\d+)?$");
 
     /**
      * Test if the passed value is a floating point number, i.e. a float, double
@@ -356,19 +360,11 @@ public class JexlArithmetic {
         if (val instanceof Float || val instanceof Double) {
             return true;
         }
-        if (val instanceof String) {
-            String str = (String) val;
-            for(int c = 0; c < str.length(); ++c) {
-                char ch = str.charAt(c);
-                // we need at least a marker that says it is a float
-                if (ch == '.' || ch == 'E' || ch == 'e') {
-                    return FLOAT_PATTERN.matcher(str).matches();
-                }
-                // and it must be a number
-                if (ch != '+' && ch != '-' && ch < '0' && ch > '9') {
-                    break;
-                }
-            }
+        if (val instanceof CharSequence) {
+            final Matcher m = FLOAT_PATTERN.matcher((CharSequence) val);
+            // first group is decimal, second is exponent;
+            // one of them must exist hence start({1,2}) >= 0
+            return m.matches() && (m.start(1) >= 0 || m.start(2) >= 0);
         }
         return false;
     }
@@ -414,7 +410,7 @@ public class JexlArithmetic {
 
     /**
      * Whether we consider the narrow class as a potential candidate for narrowing the source.
-     * 
+     *
      * @param narrow the target narrow class
      * @param source the orginal source class
      * @return true if attempt to narrow source to target is accepted
@@ -425,7 +421,7 @@ public class JexlArithmetic {
 
     /**
      * Given a Number, return back the value attempting to narrow it to a target class.
-     * 
+     *
      * @param original the original number
      * @param narrow   the attempted target class
      * @return the narrowed number or the source if no narrowing was possible
@@ -502,7 +498,7 @@ public class JexlArithmetic {
      * if either arguments is a BigInteger, no narrowing will occur
      * if either arguments is a Long, no narrowing to Integer will occur
      * </p>
-     * 
+     *
      * @param lhs  the left hand side operand that lead to the bigi result
      * @param rhs  the right hand side operand that lead to the bigi result
      * @param bigi the BigInteger to narrow
@@ -554,7 +550,7 @@ public class JexlArithmetic {
 
     /**
      * Replace all numbers in an arguments array with the smallest type that will fit.
-     * 
+     *
      * @param args the argument array
      * @return true if some arguments were narrowed and args array is modified,
      *         false if no narrowing occurred and args array has not been modified
@@ -581,7 +577,7 @@ public class JexlArithmetic {
      * If any numeric add fails on coercion to the appropriate type,
      * treat as Strings and do concatenation.
      * </p>
-     * 
+     *
      * @param left  left argument
      * @param right  right argument
      * @return left + right.
@@ -624,7 +620,7 @@ public class JexlArithmetic {
 
     /**
      * Divide the left value by the right.
-     * 
+     *
      * @param left  left argument
      * @param right  right argument
      * @return left / right
@@ -665,7 +661,7 @@ public class JexlArithmetic {
 
     /**
      * left value modulo right.
-     * 
+     *
      * @param left  left argument
      * @param right  right argument
      * @return left % right
@@ -706,7 +702,7 @@ public class JexlArithmetic {
 
     /**
      * Multiply the left value by the right.
-     * 
+     *
      * @param left  left argument
      * @param right  right argument
      * @return left * right.
@@ -737,7 +733,7 @@ public class JexlArithmetic {
 
     /**
      * Subtract the right value from the left.
-     * 
+     *
      * @param left  left argument
      * @param right  right argument
      * @return left - right.
@@ -768,7 +764,7 @@ public class JexlArithmetic {
 
     /**
      * Negates a value (unary minus for numbers).
-     * 
+     *
      * @param val the value to negate
      * @return the negated value
      */
@@ -799,7 +795,7 @@ public class JexlArithmetic {
      * Test if left contains right (right matches/in left).
      * <p>Beware that this method arguments are the opposite of the operator arguments.
      * 'x in y' means 'y contains x'.</p>
-     * 
+     *
      * @param container the container
      * @param value the value
      * @return test result or null if there is no arithmetic solution
@@ -933,7 +929,7 @@ public class JexlArithmetic {
 
     /**
      * Performs a bitwise and.
-     * 
+     *
      * @param left  the left operand
      * @param right the right operator
      * @return left &amp; right
@@ -946,7 +942,7 @@ public class JexlArithmetic {
 
     /**
      * Performs a bitwise or.
-     * 
+     *
      * @param left  the left operand
      * @param right the right operator
      * @return left | right
@@ -959,7 +955,7 @@ public class JexlArithmetic {
 
     /**
      * Performs a bitwise xor.
-     * 
+     *
      * @param left  the left operand
      * @param right the right operator
      * @return left ^ right
@@ -972,7 +968,7 @@ public class JexlArithmetic {
 
     /**
      * Performs a bitwise complement.
-     * 
+     *
      * @param val the operand
      * @return ~val
      */
@@ -983,7 +979,7 @@ public class JexlArithmetic {
 
     /**
      * Performs a logical not.
-     * 
+     *
      * @param val the operand
      * @return !val
      */
@@ -993,7 +989,7 @@ public class JexlArithmetic {
 
     /**
      * Performs a comparison.
-     * 
+     *
      * @param left     the left operand
      * @param right    the right operator
      * @param operator the operator
@@ -1327,7 +1323,7 @@ public class JexlArithmetic {
      * 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
@@ -1399,7 +1395,7 @@ public class JexlArithmetic {
 
     /**
      * Use or overload or() instead.
-     * 
+     *
      * @param lhs left hand side
      * @param rhs right hand side
      * @return lhs | rhs
@@ -1413,7 +1409,7 @@ public class JexlArithmetic {
 
     /**
      * Use or overload xor() instead.
-     * 
+     *
      * @param lhs left hand side
      * @param rhs right hand side
      * @return lhs ^ rhs
@@ -1427,7 +1423,7 @@ public class JexlArithmetic {
 
     /**
      * Use or overload not() instead.
-     * 
+     *
      * @param arg argument
      * @return !arg
      * @see JexlArithmetic#not
@@ -1440,7 +1436,7 @@ public class JexlArithmetic {
 
     /**
      * Use or overload contains() instead.
-     * 
+     *
      * @param lhs left hand side
      * @param rhs right hand side
      * @return contains(rhs, lhs)

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java?rev=1731915&r1=1731914&r2=1731915&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java Tue Feb 23 18:01:36 2016
@@ -548,11 +548,24 @@ public class ArithmeticTest extends Jexl
         Assert.assertFalse(ja.isFloatingPointNumber("+10.2a+34"));
         Assert.assertFalse(ja.isFloatingPointNumber("0"));
         Assert.assertFalse(ja.isFloatingPointNumber("1"));
+        Assert.assertFalse(ja.isFloatingPointNumber("12A"));
+        Assert.assertFalse(ja.isFloatingPointNumber("2F3"));
+        Assert.assertFalse(ja.isFloatingPointNumber("23"));
+        Assert.assertFalse(ja.isFloatingPointNumber("+3"));
+        Assert.assertFalse(ja.isFloatingPointNumber("+34"));
+        Assert.assertFalse(ja.isFloatingPointNumber("+3-4"));
+        Assert.assertFalse(ja.isFloatingPointNumber("+3.-4"));
+        Assert.assertFalse(ja.isFloatingPointNumber("3ee4"));
 
         Assert.assertTrue(ja.isFloatingPointNumber("0."));
         Assert.assertTrue(ja.isFloatingPointNumber("1."));
         Assert.assertTrue(ja.isFloatingPointNumber("1.2"));
         Assert.assertTrue(ja.isFloatingPointNumber("1.2e3"));
+        Assert.assertTrue(ja.isFloatingPointNumber("2e3"));
+        Assert.assertTrue(ja.isFloatingPointNumber("+2e-3"));
+        Assert.assertTrue(ja.isFloatingPointNumber("+23E-34"));
+        Assert.assertTrue(ja.isFloatingPointNumber("+23.E-34"));
+        Assert.assertTrue(ja.isFloatingPointNumber("-23.4E+45"));
         Assert.assertTrue(ja.isFloatingPointNumber("1.2e34"));
         Assert.assertTrue(ja.isFloatingPointNumber("10.2e34"));
         Assert.assertTrue(ja.isFloatingPointNumber("+10.2e34"));
@@ -1297,4 +1310,5 @@ public class ArithmeticTest extends Jexl
         Assert.assertEquals(BigDecimal.valueOf(0.), ja.toBigDecimal(false));
     }
 
+
 }