On 12/11/16 03:23, John Rose wrote: > On Nov 11, 2016, at 7:09 AM, fo...@univ-mlv.fr > <mailto:fo...@univ-mlv.fr> wrote: >> MH.invokeWithArguments takes an array of arguments but because it is >> specified as a varargs you may think that it works like Method.invoke, >> but it is a trap, >> it takes the receiver and the arguments altogether into the same array. > > Thanks, Remi. That should fix the problem.
I'm not sure Remi's answer exactly addresses my question exactly as he explained what happens when there is a receiver for the call and my problem case is a static call. Anyway, I think I have got the picture and now know what is wrong. > We thought a little bit about adding more overloadings to > invokeWithArguments, > such as one that works like Method.invoke (one prepended argument). > The general case would be making invokeWithArguments be > signature-polymorphic, > with an on-the-fly asSpreader transform on the way through. > > But, such extra generality would simplify only a few use cases, and on the > other hand it would probably create plenty of confusion whenever the target > method is *also* a varargs method. My problem was that the String[] argument I was passing to Arrays.asList got wrapped in an enclosing Object[] array. That's because the method has a varargs signature and when you call the method handle returned by findStatic or findVirtual the arguments are expected to be provided unwrapped in the invoke call. Whereas a method handle for a method with a trailing Object[] argument (naturally) expects the argument to contain the relevant Objects wrapped in an Object[]. This is where the disparity with reflective invocation occurs where the varargs arguments must be provided pre-wrapped to the reflective invoke call. So, (excusing the expository-but-fake array literals used to show supplied arguments) where I reflectively call method.invoke(["first", "second", third"]) the corresponding handle call would be expected to be handle.invokeWithArguments("first", "second", "third") Similary, with a varargs instance method (let's call it Foo.foo(Object...) where the reflective call would be method.invoke(foo, ["first", "second", third"]) the corresponding handle call would be either handle.invokeWithArguments(foo, "first", "second", "third") or handle.bindTo(foo).invokeWithArguments("first", "second", "third") (I think that was what Remi was getting at :-) Of course, since I package the arguments in generci code and then invoke the method in code specific to JDK8[-] or JDK9[+] I am stuck with an Object for the receiver (or null for a static call) and an Object[] for the arguments. Hence, I cannot actually supply the arguments one by one in the method handle call. The fix I found is to detect the case where a method is varargs and in that case use method asfixedArity() to convert the method handle retrieved by findStatic or findVirtual to one which accepts the arguments pre-wrapped. So, where I currently have the following reflective code: Object receiver = ... Object[] args = ... Method method = ... boolean isStatic = ... if (isStatic) { method.invoke(null, args); } else { method.invoke(receiver, args); } I simply need to replace the latter 5 lines as . . . MethodType methodType = MethodType.methodType(method.getReturnType(), method.getParameterTypes()); MethodHandle handle; if (isStatic) { handle = theLookup.findStatic(method.getDeclaringClass(), method.getName(), methodType); } else { handle = theLookup.findVirtual(method.getDeclaringClass(), method.getName(), methodType); } if (method.isVarArgs()) { handle = handle.asfixedArity(); } if (isStatic) { handle.invokeWithArguments(args); } else { handle.bindTo(receiver).invokeWithArguments(args); } This appears to have resolved my problem. regards, Andrew Dinn ----------- Senior Principal Software Engineer Red Hat UK Ltd Registered in England and Wales under Company Registration No. 03798903 Directors: Michael Cunningham, Michael ("Mike") O'Neill, Eric Shander