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 {