Author: henrib
Date: Sat May  1 09:48:56 2010
New Revision: 939962

URL: http://svn.apache.org/viewvc?rev=939962&view=rev
Log:
JEXL-101: fixed varargs handling in MethodExecutor and MethodKey; added test

Modified:
    
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/internal/MethodExecutor.java
    
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/internal/introspection/MethodKey.java
    
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/MethodTest.java

Modified: 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/internal/MethodExecutor.java
URL: 
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/internal/MethodExecutor.java?rev=939962&r1=939961&r2=939962&view=diff
==============================================================================
--- 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/internal/MethodExecutor.java
 (original)
+++ 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/internal/MethodExecutor.java
 Sat May  1 09:48:56 2010
@@ -67,13 +67,13 @@ public final class MethodExecutor extend
 
     /** {...@inheritdoc} */
     @Override
-    public Object tryExecute(String name, Object o, Object[] args) {
+    public Object tryExecute(String name, Object obj, Object[] args) {
         MethodKey tkey = new MethodKey(name, args);
         // let's assume that invocation will fly if the declaring class is the
         // same and arguments have the same type
-        if (objectClass.equals(o.getClass()) && tkey.equals(key)) {
+        if (objectClass.equals(obj.getClass()) && tkey.equals(key)) {
             try {
-                return execute(o, args);
+                return execute(obj, args);
             } catch (InvocationTargetException xinvoke) {
                 return TRY_FAILED; // fail
             } catch (IllegalAccessException xill) {
@@ -127,35 +127,28 @@ public final class MethodExecutor extend
      * to fit the method declaration.
      */
     protected Object[] handleVarArg(Class<?> type, int index, Object[] actual) 
{
-        // if no values are being passed into the vararg
-        if (actual.length == index) {
-            // create an empty array of the expected type
-            actual = new Object[]{Array.newInstance(type, 0)};
-        } else if (actual.length == index + 1) {
-            // if one value is being passed into the vararg
-            // make sure the last arg is an array of the expected type
-            if (MethodKey.isInvocationConvertible(type,
-                    actual[index].getClass(),
-                    false)) {
-                // create a 1-length array to hold and replace the last param
+        final int size = actual.length - index;
+        // if no values are being passed into the vararg, size == 0
+        if (size == 1) {
+            // if one non-null value is being passed into the vararg,
+            // make the last arg an array of the expected type
+            if (actual[index] != null) {
+                // create a 1-length array to hold and replace the last 
argument
                 Object lastActual = Array.newInstance(type, 1);
                 Array.set(lastActual, 0, actual[index]);
                 actual[index] = lastActual;
             }
-        } else if (actual.length > index + 1) {
-            // if multiple values are being passed into the vararg
-            // put the last and extra actual in an array of the expected type
-            int size = actual.length - index;
+        } else {
+            // if no or multiple values are being passed into the vararg,
+            // put them in an array of the expected type
             Object lastActual = Array.newInstance(type, size);
             for (int i = 0; i < size; i++) {
                 Array.set(lastActual, i, actual[index + i]);
             }
 
-            // put all into a new actual array of the appropriate size
+            // put all arguments into a new actual array of the appropriate 
size
             Object[] newActual = new Object[index + 1];
-            for (int i = 0; i < index; i++) {
-                newActual[i] = actual[i];
-            }
+            System.arraycopy(actual, 0, newActual, 0, index);
             newActual[index] = lastActual;
 
             // replace the old actual array

Modified: 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/internal/introspection/MethodKey.java
URL: 
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/internal/introspection/MethodKey.java?rev=939962&r1=939961&r2=939962&view=diff
==============================================================================
--- 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/internal/introspection/MethodKey.java
 (original)
+++ 
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/internal/introspection/MethodKey.java
 Sat May  1 09:48:56 2010
@@ -542,13 +542,11 @@ public final class MethodKey {
          */
         private boolean isApplicable(T method, Class<?>[] classes) {
             Class<?>[] methodArgs = getParameterTypes(method);
-
-            if (methodArgs.length > classes.length) {
-                // if there's just one more methodArg than class arg
-                // and the last methodArg is an array, then treat it as a 
vararg
-                return methodArgs.length == classes.length + 1 && 
methodArgs[methodArgs.length - 1].isArray();
-            }
-            if (methodArgs.length == classes.length) {
+            // if samee number or args or
+            // there's just one more methodArg than class arg
+            // and the last methodArg is an array, then treat it as a vararg
+            if (methodArgs.length == classes.length
+                || methodArgs.length == classes.length + 1 && 
methodArgs[methodArgs.length - 1].isArray()) {
                 // this will properly match when the last methodArg
                 // is an array/varargs and the last class is the type of array
                 // (e.g. String when the method is expecting String...)

Modified: 
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/MethodTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/MethodTest.java?rev=939962&r1=939961&r2=939962&view=diff
==============================================================================
--- 
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/MethodTest.java
 (original)
+++ 
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/MethodTest.java
 Sat May  1 09:48:56 2010
@@ -29,9 +29,33 @@ public class MethodTest extends JexlTest
 
     private static final String METHOD_STRING = "Method string";
 
-    public static class TestClass {
-        public String testVarArgs(Integer[] args) {
-            return "Test";
+    public static class VarArgs {
+        public String callInts(Integer... args) {
+            int result = 0;
+            for (int i = 0; i < args.length; i++) {
+                result += args[i].intValue();
+            }
+            return "Varargs:"+result;
+        }
+
+        public String callMixed(Integer fixed, Integer... args) {
+            int result = fixed.intValue();
+            if (args != null) {
+                for (int i = 0; i < args.length; i++) {
+                    result += args[i].intValue();
+                }
+            }
+            return "Mixed:"+result;
+        }
+        
+        public String callMixed(String mixed, Integer... args) {
+            int result = 0;
+            if (args != null) {
+                for (int arg : args) {
+                    result += arg;
+                }
+            }
+            return mixed+":"+result;
         }
     }
 
@@ -74,8 +98,26 @@ public class MethodTest extends JexlTest
     }
 
     public void testCallVarArgMethod() throws Exception {
-        asserter.setVariable("test", new TestClass());
-        asserter.assertExpression("test.testVarArgs(1,2,3,4,5)", "Test");
+        asserter.setVariable("test", new VarArgs());
+        asserter.assertExpression("test.callInts()", "Varargs:0");
+        asserter.assertExpression("test.callInts(1)", "Varargs:1");
+        asserter.assertExpression("test.callInts(1,2,3,4,5)", "Varargs:15");
+    }
+
+    public void testCallMixedVarArgMethod() throws Exception {
+        asserter.setVariable("test", new VarArgs());
+        asserter.assertExpression("test.callMixed(1)", "Mixed:1");
+        asserter.assertExpression("test.callMixed(1, null)", "Mixed:1");
+        asserter.assertExpression("test.callMixed(1,2)", "Mixed:3");
+        asserter.assertExpression("test.callMixed(1,2,3,4,5)", "Mixed:15");
+    }
+
+    public void testCallJexlVarArgMethod() throws Exception {
+        asserter.setVariable("test", new VarArgs());
+        asserter.assertExpression("test.callMixed('jexl')", "jexl:0");
+        asserter.assertExpression("test.callMixed('jexl', null)", "jexl:0");
+        asserter.assertExpression("test.callMixed('jexl', 2)", "jexl:2");
+        asserter.assertExpression("test.callMixed('jexl',2,3,4,5)", "jexl:14");
     }
 
     public void testInvoke() throws Exception {


Reply via email to