A pure Java example with reflective access behaving differently with invokeWithArguments() compared to core reflection's invoke() (Re: Strange observation: MethodHandle.invokeWithArguments() would not work, whereas Method.invoke() would with the very same arguments

Rony G. Flatscher Rony.Flatscher at wu.ac.at
Fri Jun 8 10:07:53 UTC 2018


On 11.03.2018 20:22, Rony G. Flatscher wrote:
> Well, still trying to find out what the reason is, that core reflection's invoke behaves
> differently to MethodHandle's invokeWithArguments in one single case so far (using the method
> java.utli.Arrays.asList(...)).
>
> Here is a little Java program that excercises reflective access to
> "java.util.Arrays.asList​(T... a)" using core reflection, i.e. "Method.invoke​(Object obj,
> Object... args)" and "MethodHandle.invokeWithArguments​(Object... arguments)":
>
>     import java.util.*;
>
>     import java.lang.reflect.*;
>     import java.lang.invoke.*;
>
>     class DemoAsListProblem
>     {
>         public static void main (String args[])
>         {
>             String arrNames[]=new String[] { "anne", "bert", "celine"};
>             System.out.println("[1] (main) arrNames=\""+arrNames+"\", .toString()=\""+arrNames.toString()+"\"");
>             List listNames=Arrays.asList(arrNames);
>             System.out.println("[2] (main) after invoking Arrays.asList(arrNames), listNames=\""+listNames+"\"");
>             System.out.println("\ninvoking testReflective() ...\n");
>
>             testReflective();
>         }
>
>         public static void testReflective()
>         {
>             String arrNames[]=new String[] { "anne", "bert", "celine"};
>             System.out.println("[3] (testReflective) arrNames=\""+arrNames+"\", .toString()=\""+arrNames.toString()+"\"");
>
>             Method methAsList=null;
>             List listNames=null;
>             try {
>                 Class paramTypes[]=new Class[] { (new Object[0]).getClass() };
>                 methAsList=Arrays.class.getDeclaredMethod("asList", paramTypes);
>                 System.out.println("--- (core reflection) Method object asList: "+methAsList);
>                 System.out.println("\n--- (core reflection) now invoking Arrays.asList() via Method.invoke(...):");
>
>                 listNames=(List) methAsList.invoke( null, (Object[]) new Object[]{arrNames} );   // static method
>                 System.out.println("[4a] --- (CR) methAsList.invoke( null, (Object[]) new Object[]{arrNames} ) -> listNames=\""+listNames+"\"");
>
>                 listNames=(List) methAsList.invoke( null, (Object)   new Object[]{arrNames} );   // static method
>                 System.out.println("[4b] --- (CR) methAsList.invoke( null, (Object)   new Object[]{arrNames} ) -> listNames=\""+listNames+"\"");
>
>     // "java.lang.IllegalArgumentException: wrong number of arguments":
>     //            listNames=(List) methAsList.invoke( null, (Object[]) arrNames );   // static method
>     //            System.out.println("[5a] --- (CR) methAsList.invoke( null, (Object[]) arrNames ) -> listNames=\""+listNames+"\"");
>
>                 listNames=(List) methAsList.invoke( null, (Object)   arrNames );   // static method
>                 System.out.println("[5b] --- (CR) methAsList.invoke( null, (Object)   arrNames )               -> listNames=\""+listNames+"\"");
>             }
>             catch (Throwable t)
>             {
>                 System.err.println("oops #1: "+t);
>                 t.printStackTrace();
>                 System.exit(-1);
>             }
>
>             System.out.println("\n--- (MH) now invoking Arrays.asList() via MethodHandle.invokeWithArguments(...):");
>             MethodHandles.Lookup lookup=MethodHandles.lookup();
>             MethodHandle mh=null;
>             try {
>                 mh=lookup.unreflect(methAsList);
>                 System.out.println("--- (MH) unreflected MethodHandle mh: "+mh);
>
>                 listNames=(List) mh.invokeWithArguments( (Object[]) new Object[]{arrNames} );
>                 System.out.println("[6a] --- (MH) mh.invokeWithArguments(  (Object[]) new Object[]{arrNames} ) -> listNames=\""+listNames+"\"");
>
>                 listNames=(List) mh.invokeWithArguments( (Object) new Object[]{arrNames} );
>                 System.out.println("[6b] --- (MH) mh.invokeWithArguments(  (Object)   new Object[]{arrNames} ) -> listNames=\""+listNames+"\"");
>
>                 listNames=(List) mh.invokeWithArguments( (Object[]) arrNames );
>                 System.out.println("[7a] --- (MH) mh.invokeWithArguments(  (Object[]) arrNames )               -> listNames=\""+listNames+"\"");
>
>                 listNames=(List) mh.invokeWithArguments( (Object) arrNames );
>                 System.out.println("[7b] --- (MH) mh.invokeWithArguments(  (Object)   arrNames )               -> listNames=\""+listNames+"\"");
>
>             }
>             catch (Throwable t)
>             {
>                 System.err.println("oops #2: "+t);
>                 t.printStackTrace();
>                 System.exit(-2);
>             }
>         }
>     }
>
> Compiling and running it under 9.0.4 yields the following output:
>
>     [1] (main) arrNames="[Ljava.lang.String;@27ddd392", .toString()="[Ljava.lang.String;@27ddd392"
>     [2] (main) after invoking Arrays.asList(arrNames), listNames="[anne, bert, celine]"
>
>     invoking testReflective() ...
>
>     [3] (testReflective) arrNames="[Ljava.lang.String;@2a18f23c", .toString()="[Ljava.lang.String;@2a18f23c"
>     --- (core reflection) Method object asList: public static java.util.List java.util.Arrays.asList(java.lang.Object[])
>
>     --- (core reflection) now invoking Arrays.asList() via Method.invoke(...):
>     [4a] --- (CR) methAsList.invoke( null, (Object[]) new Object[]{arrNames} ) -> listNames="[anne, bert, celine]"
>     [4b] --- (CR) methAsList.invoke( null, (Object)   new Object[]{arrNames} ) -> listNames="[[Ljava.lang.String;@2a18f23c]"
>     [5b] --- (CR) methAsList.invoke( null, (Object)   arrNames )               -> listNames="[anne, bert, celine]"
>
>     --- (MH) now invoking Arrays.asList() via MethodHandle.invokeWithArguments(...):
>     --- (MH) unreflected MethodHandle mh: MethodHandle(Object[])List
>     [6a] --- (MH) mh.invokeWithArguments(  (Object[]) new Object[]{arrNames} ) -> listNames="[[Ljava.lang.String;@2a18f23c]"
>     [6b] --- (MH) mh.invokeWithArguments(  (Object)   new Object[]{arrNames} ) -> listNames="[[Ljava.lang.Object;@13a57a3b]"
>     [7a] --- (MH) mh.invokeWithArguments(  (Object[]) arrNames )               -> listNames="[anne, bert, celine]"
>     [7b] --- (MH) mh.invokeWithArguments(  (Object)   arrNames )               -> listNames="[[Ljava.lang.String;@2a18f23c]"
>
> So a String array is turned into a List using Arrays.asList(strArray). Doing it with core
> reflection yields different results to doing it with invokeWithArguments().
>
> I would have expected that [4a] and [6a] would behave the same.
>
> Using reflective invoke() and invokeWithArguments() has been working for my bridge for all the
> test units (using literally the same arguments in both cases) interchangeably, the one exception
> is Arrays.asList().
>
> Maybe I am not seeing the obvious (having done too much "close-up tests" for quite some time now).
> So any hint, insight, help would be really appreciated!
>
> ---rony
As a few months have gone by without any follow-ups, I have been wondering whether there is a
solution at all, if this is a problem rooted in the current implementation of MethodHandle methods
not being 100% compatible with reflective invoke (which may imply that one needs to stick to use
reflective invoke and forgo MethodHandle invokes for good).

---rony

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/mlvm-dev/attachments/20180608/8eb3698d/attachment.html>


More information about the mlvm-dev mailing list