Commits

Anonymous committed 5411ee4

More OgnlRuntime fixes for varargs handling.

Comments (0)

Files changed (10)

src/java/ognl/OgnlRuntime.java

     {
         Object result;
         boolean wasAccessible = true;
-        Object[] arguments = argsArray;
 
         synchronized(method) {
 
                 }
             }
 
-            if (isJdk15() && method.isVarArgs()) {
-                arguments = new Object[] { argsArray };
-            }
-
-            result = method.invoke(target, arguments);
+            result = method.invoke(target, argsArray);
             if (!wasAccessible) {
                 ((AccessibleObject) method).setAccessible(false);
             }
                 if (index >= classes.length){
                     break;
                 }
-                result = isTypeCompatible(args[index], classes[index]) || classes[index].isArray();
+
+                result = isTypeCompatible(args[index], classes[index]);
+
+                if (!result && classes[index].isArray()) {
+                    result = isTypeCompatible(args[index], classes[index].getComponentType());
+                }
+
+                //result = isTypeCompatible(args[index], classes[index]) || classes[index].isArray();
             }
         } else {
             for (int index = 0, count = args.length; result && (index < count); ++index) {
                 throw new NoSuchMethodException(className + methodName + "(" + buffer + ")");
             }
 
-            return invokeMethod(target, method, actualArgs);
+            Object[] convertedArgs = actualArgs;
+
+            if (isJdk15() && method.isVarArgs())
+            {
+                Class[] parmTypes = method.getParameterTypes();
+
+                // split arguments in to two dimensional array for varargs reflection invocation
+                // where it is expected that the parameter passed in to invoke the method
+                // will look like "new Object[] { arrayOfNonVarArgsArguments, arrayOfVarArgsArguments }"
+                
+                for (int i=0; i < parmTypes.length; i++)
+                {
+                    if (parmTypes[i].isArray())
+                    {
+                        convertedArgs = new Object[i + 1];
+                        System.arraycopy(actualArgs, 0, convertedArgs, 0, convertedArgs.length);
+
+                        Object[] varArgs;
+
+                        // if they passed in varargs arguments grab them and dump in to new varargs array
+                        
+                        if (actualArgs.length > i)
+                        {
+                            ArrayList varArgsList = new ArrayList();
+                            for (int j=i; j < actualArgs.length; j++)
+                            {
+                                if (actualArgs[j] != null)
+                                {
+                                    varArgsList.add(actualArgs[j]);
+                                }
+                            }
+                            
+                            varArgs = varArgsList.toArray();
+                        } else
+                        {
+                            varArgs = new Object[0];
+                        }
+
+                        convertedArgs[i] = varArgs;
+                        break;
+                    }
+                }
+            }
+
+            return invokeMethod(target, method, convertedArgs);
 
         } catch (NoSuchMethodException e) {
             reason = e;

src/test/java/ognl/TestOgnlRuntime.java

         assertEquals(Ognl.getValue("value", context, root), "12__");
     }
 
+    public void test_Call_Method_VarArgs()
+            throws Exception
+    {
+        OgnlContext context = (OgnlContext) Ognl.createDefaultContext(null);
+        GenericService service = new GenericServiceImpl();
+
+        GameGenericObject argument = new GameGenericObject();
+
+        Object[] args = OgnlRuntime.getObjectArrayPool().create(2);
+        args[0] = argument;
+
+        assertEquals("Halo 3", OgnlRuntime.callMethod(context, service, "getFullMessageFor", args));
+    }
+
     public void test_Class_Cache_Inspector()
             throws Exception
     {

src/test/java/org/ognl/test/MethodTest.java

 package org.ognl.test;
 
 import junit.framework.TestSuite;
-import org.ognl.test.objects.ListSource;
-import org.ognl.test.objects.ListSourceImpl;
-import org.ognl.test.objects.Simple;
+import org.ognl.test.objects.*;
 
 public class MethodTest extends OgnlTestCase
 {
 
     private static Simple ROOT = new Simple();
     private static ListSource LIST = new ListSourceImpl();
+    private static BaseGeneric GENERIC = new GameGeneric();
 
     private static Object[][] TESTS = {
             { "hashCode()", new Integer(ROOT.hashCode()) } ,
             { "isEditorDisabled()", Boolean.FALSE},
             { LIST, "addValue(name)", Boolean.TRUE},
             { "getDisplayValue(methodsTest.allowDisplay)", "test"},
-            { "isThisVarArgsWorking(three, rootValue)", Boolean.TRUE}
+            { "isThisVarArgsWorking(three, rootValue)", Boolean.TRUE},
+            { GENERIC, "message + ' ' + service.getFullMessageFor(value, null)", "Message Halo 3"}
     };
 
     public static class A

src/test/java/org/ognl/test/objects/BaseGeneric.java

+package org.ognl.test.objects;
+
+/**
+ * Used to test ognl handling of java generics.
+ */
+public class BaseGeneric<E extends GenericObject> {
+
+    E _value;
+    GenericService _service;
+
+    public BaseGeneric()
+    {
+        _service = new GenericServiceImpl();
+    }
+
+    public String getMessage()
+    {
+        return "Message";
+    }
+
+    public E getValue()
+    {
+        return _value;
+    }
+
+    public GenericService getService()
+    {
+        return _service;
+    }
+}

src/test/java/org/ognl/test/objects/GameGeneric.java

+package org.ognl.test.objects;
+
+/**
+ *
+ */
+public class GameGeneric extends BaseGeneric<GameGenericObject> {
+
+    public GameGeneric()
+    {
+        _value = new GameGenericObject();
+    }
+}

src/test/java/org/ognl/test/objects/GameGenericObject.java

+package org.ognl.test.objects;
+
+/**
+ *
+ */
+public class GameGenericObject implements GenericObject {
+
+    public GameGenericObject()
+    {
+        super();
+    }
+
+    public int getId()
+    {
+        return 20;
+    }
+
+    public String getDisplayName()
+    {
+        return "Halo 3";
+    }
+}

src/test/java/org/ognl/test/objects/GenericObject.java

+package org.ognl.test.objects;
+
+/**
+ * Used by {@link BaseGeneric} to reference a class type.
+ */
+public interface GenericObject {
+
+    int getId();
+
+    String getDisplayName();
+}

src/test/java/org/ognl/test/objects/GenericService.java

+package org.ognl.test.objects;
+
+/**
+ *
+ */
+public interface GenericService {
+
+    String getFullMessageFor(PersonGenericObject person, Object...arguments);
+
+    String getFullMessageFor(GameGenericObject game, Object...arguments);
+}

src/test/java/org/ognl/test/objects/GenericServiceImpl.java

+package org.ognl.test.objects;
+
+/**
+ *
+ */
+public class GenericServiceImpl implements GenericService {
+
+    public String getFullMessageFor(PersonGenericObject person, Object... arguments)
+    {
+        return person.getDisplayName();
+    }
+
+    public String getFullMessageFor(GameGenericObject game, Object... arguments)
+    {
+        return game.getDisplayName();
+    }
+}

src/test/java/org/ognl/test/objects/PersonGenericObject.java

+package org.ognl.test.objects;
+
+/**
+ *
+ */
+public class PersonGenericObject implements GenericObject {
+
+    public int getId()
+    {
+        return 1;
+    }
+
+    public String getDisplayName()
+    {
+        return "Henry Collins";
+    }
+}