Just to conclude: this is something that has nothing to do with jigsaw per se.

If interested you could look further to mlvm-dev ("Da Vinci Machine Project"), 
here two respective
links: <http://mail.openjdk.java.net/pipermail/mlvm-dev/2018-March/006838.html> 
and a pure Java
example pointing at the problem:
<http://mail.openjdk.java.net/pipermail/mlvm-dev/2018-March/006846.html>.

---rony


On 12.02.2018 20:59, Rony G. Flatscher wrote:
> In the process of adapting pure reflective code (a Rexx-Java bridge) to use 
> MethodHandles on Java 9
> instead, everything seems to be working out so far.
>
> In principle all invocations on the Java side are carried out by first using 
> java.lang.reflect
> (Field, Method, Constructor) using the supplied arguments (if the arguments 
> can be coerced to the
> respective parameterTypes it gets selected for invocation)  and if a 
> candidate is found an
> appropriate MethodHandle gets created, which then gets used to invoke the 
> operation supplying the
> coerced arguments, if any. Over the weekend I finalized the basic changes and 
> started to test
> against a set of sample/demo applications.
>
> ---
>
> While testing a rather complex one (an adaption of the JavaFX address book 
> example enhanced with a
> BarChart, [1]), that exhibits a very strange behavior: when setting the 
> values for the CategoryAxis
> supplying an ObservableList of the month names in the current Locale, using a 
> MethodHandle and
> invoking it with invokeWithArguments() would yield (debug output):
>
>     // // // RexxReflectJava9.processMethod(), ARRIVED: -> [INVOKE], 
> tmpMethod=[public final void
>     
> javafx.scene.chart.CategoryAxis.setCategories(javafx.collections.ObservableList)]:
>     method=[SETCATEGORIES] in
>     
> object=[rru.rexxArgs[1]="javafx.scene.chart.CategoryAxis@83278e1"/rru.bean="CategoryAxis[id=xAxis,
>     styleClass=axis]"]
>
>     // // // RexxReflectJava9.processMethod(),
>     coercedArgs=[[[Ljava.lang.String;@57cfe770]].getClass().toString()=class 
> [Ljava.lang.Object;,
>              parameterTypes=[interface
>     javafx.collections.ObservableList].getClass().toString()=class 
> [Ljava.lang.Class;:,
>              
> rru.funcArgs=[[[Ljava.lang.String;@57cfe770]].getClass().toString()=class
>     [Ljava.lang.Object;
>
>     // // :( RexxReflectJava9.processMethod(), MethodType for Method [public 
> final void
>     
> javafx.scene.chart.CategoryAxis.setCategories(javafx.collections.ObservableList)]:
>     "(ObservableList)void"
>
>     // // :( RexxReflectJava9.processMethod(): INSTANCE, 
> mh.bindTo("CategoryAxis[id=xAxis,
>     styleClass=axis]/class 
> javafx.scene.chart.CategoryAxis").invokeWithArguments(...)
>
>     // :) :) RexxReflectJava9.processMethod(), MethodHandle
>     "MethodHandle(CategoryAxis,ObservableList)void" invocation caused a 
> Throwable:
>     java.lang.ClassCastException: java.base/[Ljava.lang.String; cannot be 
> cast to
>     java.base/java.lang.String
>
>
> The supplied ObservableList argument represents the  month names and was 
> created with the help of
> "javafx.collections.FXCollections.observableList()" and then using its 
> "addAll(monthNames)" method
> to add the String array values returned by DateFormatSymbols.getMonths() to 
> the list.
>
> The supplied argument array "rru.funcArgs" will be coerced according to the 
> reflected
> "parameterTypes" array yielding the "coercedArgs" array; using 
> java.util.Arrays.deepToString() gives:
>
>     // // // RexxReflectJava9.processMethod(),
>     coercedArgs=[[[Ljava.lang.String;@57cfe770]].getClass().toString()=class 
> [Ljava.lang.Object;,
>              parameterTypes=[interface
>     javafx.collections.ObservableList].getClass().toString()=class 
> [Ljava.lang.Class;:,
>              
> rru.funcArgs=[[[Ljava.lang.String;@57cfe770]].getClass().toString()=class
>     [Ljava.lang.Object;
>
> ---
>
> The story is much longer but after quite long debugging sessions, I turned on 
> reflective invoke via
> tmpMethod instead of invoking the corresponding MethodHandle, which 
> (surprisingly) works.
>
> Then, in the next step doing the same invocation via the corresponding 
> MethodHandle immediately
> after the reflective invocation, allows that invocation to execute 
> successfully as well!
>
> Please note, the supplied coerced argument is in both cases the same! 
> Coercion occurs according to
> the "parameterTypes" returned by java.lang.reflect.Method which also is used 
> for creating the
> MethodType in order to use a publicLookup.findVirtual(...). Or with other 
> words: the coerced
> argument will be identical for both invocation types!
>
>
> Another strange observation in the success case is as follows: when using 
> reflective invocation by
> default (and then only invoking the MethodHandle in the special case that the 
> method "setCategories"
> is to be executed) the coerced argument supplied to 
> java.util.Arrays.deepToString() will list the
> monthnames:
>
>     // // // RexxReflectJava9.processMethod(), ARRIVED: -> [INVOKE], 
> tmpMethod=[public final void
>     
> javafx.scene.chart.CategoryAxis.setCategories(javafx.collections.ObservableList)]:
>     method=[SETCATEGORIES] in
>     
> object=[rru.rexxArgs[1]="javafx.scene.chart.CategoryAxis@2d809949"/rru.bean="CategoryAxis[id=xAxis,
>     styleClass=axis]"]
>
>     // // // RexxReflectJava9.processMethod(), coercedArgs=[[January, 
> February, March, April, May,
>     June, July, August, September, October, November, December, 
> ]].getClass().toString()=class
>     [Ljava.lang.Object;,
>              parameterTypes=[interface
>     javafx.collections.ObservableList].getClass().toString()=class 
> [Ljava.lang.Class;:,
>              rru.funcArgs=[[January, February, March, April, May, June, July, 
> August, September,
>     October, November, December, ]].getClass().toString()=class 
> [Ljava.lang.Object;
>
>     // // // RexxReflectJava9.processMethod(), bean=[CategoryAxis[id=xAxis, 
> styleClass=axis]],
>     methodName=[SETCATEGORIES], coercedArgs=[[January, February, March, 
> April, May, June, July,
>     August, September, October, November, December, ]]
>
>     // // :( RexxReflectJava9.processMethod(), MethodType for Method [public 
> final void
>     
> javafx.scene.chart.CategoryAxis.setCategories(javafx.collections.ObservableList)]:
>     "(ObservableList)void"
>
>     // // :( RexxReflectJava9.processMethod(): INSTANCE, 
> mh.bindTo("CategoryAxis[id=xAxis,
>     styleClass=axis]/class 
> javafx.scene.chart.CategoryAxis").invokeWithArguments(...)
>
>     ... add2cachedFieldsOrMethods(): rru.memberName=[SETCATEGORIES] ->
>     rru.keyMemberName=[SETCATEGORIES], rru.invocationType=[INVOKE],
>     
> cfm=[CachedFieldOrMethod[mhk=METHOD,mh=MethodHandle(CategoryAxis,ObservableList)void,parameterTypes=[interface
>     javafx.collections.ObservableList]]]
>
> I double checked that the only difference is in using 
> java.lang.reflect.Method.invoke(...) which
> makes the Throwable on the method handle invocation go away (and the 
> monthnames to be shown by
> Arrays.deepToString()).
>
> Here is the excerpt of the code section in question that allows the 
> MethodHandle mh to be invoked
> successfully with the same coerced argument:
>
>     Class<?> parameterTypes[] = tmpMethod.getParameterTypes();
>                     rru.result=tmpMethod.invoke(rru.bean,coercedArgs);      
> // java.lang.reflect.Method
>     ... cut ...
>                 Class <?> returnType=tmpMethod.getReturnType();
>                 MethodType mt = MethodType.methodType(returnType, 
> parameterTypes);
>     ... cut ...
>                // access via MethodHandle with the rights of 
> rru.firstExportedClz
>                             mh=thisLookup.findVirtual(rru.firstExportedClz, 
> methodName, mt);
>                             // mh=thisLookup.unreflect(tmpMethod);  // same 
> behaviour
>
>                     
> rru.result=mh.bindTo(rru.bean).invokeWithArguments(coercedArgs); // bind to
>     bean, invoke method
>
> Just commenting out the reflective invocation in line 2 above
> ("rru.result=tmpMethod.invoke(rru.bean,coercedArgs); ") will cause the 
> MethodHandle invocation to
> fail with the reported Throwable!
>
> --- 
>
> Also it seems that java.util.Arrays.deepToString(...) is affected by this, if 
> looking at the String
> value it produces in both cases (different number of enclosing square 
> brackets: the failing version
> has another pair of enclosing square brackets).
>
> Here the debug code for creating the above outputs ("coercedArgs" will be 
> returned by a coerce
> method and will be null, if the "rru.funcArgs" arguments from Rexx could not 
> be coerced according to
> the "parameterTypes"):
>
>     String tmpStrCoercedArgs= (coercedArgs==null ? null :
>     
> Arrays.deepToString(coercedArgs)+".getClass().toString()="+coercedArgs.getClass().toString()
>  );
>
>     System.err.println("// // // RexxReflectJava9.processMethod(), 
> coercedArgs="+tmpStrCoercedArgs
>                                                                    +",\n\t\t
>     
> parameterTypes="+Arrays.deepToString(parameterTypes)+".getClass().toString()="+parameterTypes.getClass().toString()
>                                                                    +":,\n\t\t
>     
> rru.funcArgs="+Arrays.deepToString(rru.funcArgs)+".getClass().toString()="+rru.funcArgs.getClass().toString()
>                                                                    );
>
> ---
>
> This strange observation is on Windows 7:
>
>     F:\work\svn\bsf4oorexx\trunk\bsf4oorexx.dev\source_cc>java -version
>     java version "9.0.1"
>     Java(TM) SE Runtime Environment (build 9.0.1+11)
>     Java HotSpot(TM) 64-Bit Server VM (build 9.0.1+11, mixed mode)
>
> ---
>
> Would anyone have an idea what the reason could be or have any advice?
>
> ---rony
>
> [1] Slides with the address book sample in question; look for the pictures in 
> the section starting
> at page: 
> <http://www.rexxla.org/events/2017/presentations/AutoJava-BSF4ooRexx-07-JavaFx-201711.pdf>.
>
> P.S.: Yes, the debug output could be cleaner (evolved from many permutations 
> and formatting in the
> past weeks), however this is right from the battle-field and tidying 
> everything up is next on the
> todo list.
>

Reply via email to