On 24.01.2018 20:48, Alan Bateman wrote: > On 24/01/2018 15:42, Rony G. Flatscher wrote: >> >> OK, now add to this the following class that uses p.C2 objects to access >> e.g. m() via it: >> >> G:\xfer\java9modules\03-20180124-AlanBatmanP\p>type UseC2.java >> >> public class UseC2 >> { >> public static void main (String args[]) { >> p.C2 o=new p.C2(); >> System.out.println("o="+o); >> System.out.println("o.m()="+o.m()); >> } >> } >> >> Compiling all three classes works. >> >> Running "UseC2" works and outputs: >> >> G:\xfer\java9modules\03-20180124-AlanBatmanP\p>java -cp ".;.." UseC2 >> o=p.C2@66048bfd >> o.m()=-1 >> >> So it is possible to access m() via the p.C2 object from UseC2. > That's right and this is the reason for moving to the simpler example.
--- > > To be absolutely sure then you should decompile C2.class to make sure that > there isn't a bridge > method calling C1's m2(). If you change m() to be final then that will keep > the bridge method from > complicating the picture. > > If you change UseC2 to use core reflection and you hit the issue because the > Method object you get > is p.C1.m(). Attempting to invoke this will fail with IllegalAccessException. > In your other mail > you show a code fragment where it catches exceptions and calls setAccessible > - I'll guess that > this may have been masking the issue in the Rexx bridge. The logic to find a matching Method object is to start out in the object's class for which reflective invocation is needed. Then using getDeclaredMethods() and look for the public method (with the sought name and parameters types that can be used for the supplied arguments), if not found, going up its superclass and repeating the process until a matching Method object is found. Being sure that the found public Method object is the appropriate one setAccess() makes it accessible. > For completeness then you may want to try out the new reflection API. I > realize you have to > compile to JDK 6 but I think you'll find it will work the same way as the > invokevirtual that o.m() > compiles to. It will not be a problem to supply different reflection versions after the rewrite. > MethodHandles.Lookup lookup = MethodHandles.lookup(); > MethodType mt = MethodType.methodType(int.class); > MethodHandle mh = lookup.findVirtual(p.C2.class, "m", mt); > Object res = mh.invoke(o); Thank you very much for this snippet, it really helped me a lot to explore MethodHandles in the context of my problem! After some testing, it looks like it will allow me to solve the problem, although for a price consisting of learning a totally different way (which is o.k. for me personally) of achieving what used to be simple and safe (accessing only public members via reflection), but potentially also incurring a performance penalty compared to using only reflection. The expected performance penalty would be due to the fact that reflection cannot be by passed: the Rexx bridge supplies the member's names usually in uppercase and primitive values as plain strings, such that one must use reflection to locate candidate members (need to be public and caselessly carrying the Rexx supplied member name), then check whether the Rexx supplied arguments can be coerced to the parameter types of the candidate, and if so access it; if not, check the next candidate. Now, further steps will be necessary in addition: among them create the MethodType, get the MethodHandle, render the arguments and invoke it. --- Is there a possibility to have invoke arguments to MethodHandles be relayed, say to some method RexxValue2JavaValue, such that one can receive the MethodType, the Rexx arguments and return the matching type-converted values that should then be used for the invoke operation? ---rony