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 2009/11/09 23:10:43 UTC

svn commit: r834255 - in /commons/proper/jexl/trunk/src: main/java/org/apache/commons/jexl/JexlArithmetic.java test/java/org/apache/commons/jexl/ArrayLiteralTest.java

Author: henrib
Date: Mon Nov  9 22:10:42 2009
New Revision: 834255

URL: http://svn.apache.org/viewvc?rev=834255&view=rev
Log:
Made array literals strongly typed; the code will attempt to find a common class for all elements of an array literal. Thus a ['foo', 'bar'] will create a String[ ] . If all elements are primitives of the same type, the returned array will be of that primitive type; [1, 2] will create an int[ ]. If all elements are Number (but of different classes), a Number[ ] will be returned. If all attempts fail, an  Object[ ] is returned.

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

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/JexlArithmetic.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/JexlArithmetic.java?rev=834255&r1=834254&r2=834255&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/JexlArithmetic.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl/JexlArithmetic.java Mon Nov  9 22:10:42 2009
@@ -16,6 +16,8 @@
  */
 package org.apache.commons.jexl;
 
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 
@@ -182,6 +184,59 @@
     }
 
     /**
+     * Given an array of objects, attempt to type it more strictly.
+     * <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>
+     * <li>If all objects are convertible to a primitive type, the array returned will be an array
+     * of the primitive type</li>
+     * </ul>
+     * @param untyped an untyped array
+     * @return the original array if the attempt to strictly type the array fails, a typed array otherwise
+     */
+    protected Object narrowArrayType(Object[] untyped) {
+        final int size = untyped.length;
+        Class<?> commonClass = null;
+        if (size > 0) {
+            // base common class on first entry
+            commonClass = untyped[0].getClass();
+            final boolean isNumber = Number.class.isAssignableFrom(commonClass);
+            // for all children after first...
+            for (int i = 1; i < size; i++) {
+                Class<?> eclass = untyped[i].getClass();
+                // detect same type for all elements in array
+                if (!Object.class.equals(commonClass) && !commonClass.equals(eclass)) {
+                    // if both are numbers...
+                    if (isNumber && Number.class.isAssignableFrom(eclass)) {
+                        commonClass = Number.class;
+                    } else {
+                        commonClass = Object.class;
+                    }
+                }
+            }
+            // convert array to the common class if not Object.class
+            if (!Object.class.equals(commonClass)) {
+                // if the commonClass has an equivalent primitive type, get it
+                if (isNumber) {
+                    try {
+                        Field TYPE = commonClass.getField("TYPE");
+                        commonClass = (Class<?>) TYPE.get(null);
+                    } catch (Exception xany) {
+                        // ignore
+                    }
+                }
+                // allocate and fill up the typed array
+                Object typed = Array.newInstance(commonClass, size);
+                for(int i = 0; i < size; ++i) {
+                    Array.set(typed, i, untyped[i]);
+                }
+                return typed;
+            }
+        }
+        return untyped;
+    }
+
+    /**
      * Add two values together.
      * <p>
      * If any numeric add fails on coercion to the appropriate type,

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl/ArrayLiteralTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl/ArrayLiteralTest.java?rev=834255&r1=834254&r2=834255&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl/ArrayLiteralTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl/ArrayLiteralTest.java Mon Nov  9 22:10:42 2009
@@ -19,7 +19,7 @@
 import java.util.Arrays;
 
 /**
- * Tests for map literals
+ * Tests for array literals
  * @since 2.0
  */
 public class ArrayLiteralTest extends JexlTestCase {
@@ -43,14 +43,23 @@
     }
 
     public void testLiteralWithNumbers() throws Exception {
-        Expression e = JEXL.createExpression( "[ 5 , 10 ]" );
+        Expression e = JEXL.createExpression( "[ 5.0 , 10 ]" );
         JexlContext jc = JexlHelper.createContext();
 
         Object o = e.evaluate( jc );
-        Object[] check = { Integer.valueOf(5), Integer.valueOf(10) };
+        Object[] check = { new Float(5), new Integer(10) };
         assertTrue( Arrays.equals(check, (Object[])o) );
     }
 
+    public void testLiteralWithIntegers() throws Exception {
+        Expression e = JEXL.createExpression( "[ 5 , 10 ]" );
+        JexlContext jc = JexlHelper.createContext();
+
+        Object o = e.evaluate( jc );
+        int[] check = { 5, 10 };
+        assertTrue( Arrays.equals(check, (int[])o) );
+    }
+
     public void testSizeOfSimpleArrayLiteral() throws Exception {
         Expression e = JEXL.createExpression( "size([ 'foo' , 'bar' ])" );
         JexlContext jc = JexlHelper.createContext();