New proposal for #ReflectiveAccessToNonExportedTypes: Open modules & open packages
Andrew Dinn
adinn at redhat.com
Fri Nov 18 16:43:46 UTC 2016
On 12/11/16 03:23, John Rose wrote:
> On Nov 11, 2016, at 7:09 AM, forax at univ-mlv.fr
> <mailto:forax at 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
More information about the jigsaw-dev
mailing list