Using java.awt.Toolkit.getDefaultToolkit().getScreenSize() reflectively causes InaccessibleObjectException

Peter Levart peter.levart at gmail.com
Sat Jan 7 19:54:09 UTC 2017


Hi Rony,

Implementing explicit cast is easy in this scheme (the Java side):

public static void cast(Object object, ReturnTypesList rtList, Class<?> 
typeToCastTo) throws ClassCastException {
     typeToCastTo.cast(object);
     rtList.merge(typeToCastTo);
}

Peter

On 01/07/2017 08:46 PM, Peter Levart wrote:
> Hi Rony,
>
> As with all concurrent data structures that try to optimize something, 
> you can get it wrong in the first try. Here's the corrected code:
>
> public class ReturnTypesList extends CopyOnWriteArrayList<Class<?>> {
>
>     private final Object lock = new Object();
>
>     public void merge(Class<?> newType) {
>         for (Class<?> type : this) {
>             if (newType.isAssignableFrom(type)) {
>                 // already have the same or more specific type
>                 return;
>             }
>         }
>         // we need to serialize access when modifying
>         synchronized (lock) {
>             // re-check under lock as the list might have been modified
>             for (Class<?> type : this) {
>                 if (newType.isAssignableFrom(type)) {
>                     // already have the same or more specific type
>                     return;
>                 }
>             }
>             // add newType 1st as it is the most specific type among 
> related ones
>             // this may make list appear to contain related types for 
> a brief moment
>             // but that's not a problem if the logic that looks up 
> methods can cope
>             // with it (it might find duplicate methods)
>             add(newType);
>             // 2nd remove the less specific related types
>             Iterator<Class<?>> iter = iterator();
>             while (iter.hasNext()) {
>                 Class<?> type = iter.next();
>                 if (type != newType && type.isAssignableFrom(newType)) {
>                     // newType is more specific -> remove less 
> specific one
>                     iter.remove();
>                 }
>             }
>         }
>     }
> }
>
> Regards, Peter
>
> On 01/07/2017 08:33 PM, Peter Levart wrote:
>>
>>
>> On 01/07/2017 07:25 PM, Rony G. Flatscher wrote:
>>>
>>> Hi Peter,
>>>
>>> thank you again for your effort, I really appreciate it!
>>>
>>> However, as you note at the end yourself, the problem is that any 
>>> Java object could be used concurrently in different usages of the 
>>> Java bridge, so saving the last return type with the returned object 
>>> is not feasible.
>>>
>>
>> I'm not suggesting that. Saving all most specific non-related return 
>> types is what would be needed and then using them all in sequence to 
>> search for method(s).
>>
>>> E.g. each new instance of a javax.script.RexxEngine creates a new 
>>> Rexx interpreter instance. Each Rexx interpreter instance allows any 
>>> number of Rexx threads to run concurrently and it is possible to use 
>>> the Java bridge from any of these Rexx threads concurrently and use 
>>> the (identical) Java object in different use cases (e.g. having 
>>> different Event handlers implemented in Rexx serving at the same 
>>> time different Java interfaces). Add to this the possibility that 
>>> the same is possible at the Java side, where (the same or different) 
>>> RexxEngines could get exercised in different Java threads.
>>>
>>
>> No problem. What you need is a special concurrent collection 
>> implementation that keeps all the most specific method return types 
>> you add to it which are unrelated. When types are related, you just 
>> keep the most specific one. Like this:
>>
>> public class ReturnTypesList extends CopyOnWriteArrayList<Class<?>> {
>>
>>     private final Object lock = new Object();
>>
>>     public void merge(Class<?> newType) {
>>         for (Class<?> type : this) {
>>             if (newType.isAssignableFrom(type)) {
>>                 // already have the same or more specific type
>>                 return;
>>             }
>>         }
>>         // we need to serialize access when modifying
>>         synchronized (lock) {
>>             Iterator<Class<?>> iter = iterator();
>>             while (iter.hasNext()) {
>>                 Class<?> type = iter.next();
>>                 // re-check under lock as the list might have been 
>> modified
>>                 if (newType.isAssignableFrom(type)) {
>>                     // already have the same or more specific type
>>                     return;
>>                 }
>>                 if (type != newType && type.isAssignableFrom(newType)) {
>>                     // newType is more specific -> remove less 
>> specific one
>>                     iter.remove();
>>                 }
>>             }
>>             // newType is most specific
>>             add(newType);
>>         }
>>     }
>> }
>>
>> ...use merge(method.getReturnType()) to keep the list of most 
>> specific return types updated - mostly the type will already be found 
>> in the list and the first for loop will bail out without any 
>> modification or synchronization, so this is quite scalable. When you 
>> search for method, iterate the ReturnTypesList registered with the 
>> object and collect all the methods you find on all types in the list 
>> to select the most appropriate. I think you will find that most 
>> objects will register a single method's return type. There will be 
>> rare occasions where multiple types will be registered.
>>
>> Regards, Peter
>>
>>> ---rony
>>>
>>>
>>> On 07.01.2017 19:16, Peter Levart wrote:
>>>> Hi Rony,
>>>>
>>>> On 01/07/2017 03:53 PM, Rony G. Flatscher wrote:
>>>>>
>>>>> Hi Peter,
>>>>>
>>>>> thank you very much for your efforts!
>>>>>
>>>>> However, in this context there is a problem at hand, that there is 
>>>>> no information available what Java method returned what object and 
>>>>> what cast was carried out, if any. To understand this, maybe I 
>>>>> should give a little bit more information about the Rexx-Java 
>>>>> bridge: Rexx/ooRexx (originally developed by IBM, now in 
>>>>> opensource) is an interpreter for a dynamically typed, caseless 
>>>>> programming language with a rather easy to learn syntax, yet 
>>>>> powerful implemented concepts. ooRexx is implemented in C++.
>>>>>
>>>>> The Rexx-Java-bridge uses JNI and a Java package (for ooRexx 
>>>>> programmers it is an external function package called BSF4ooRexx, 
>>>>> which allows to camouflage all of Java as the dynamically typed, 
>>>>> caseless ooRexx). It is possible with this package to create Rexx 
>>>>> proxy objects for Java objects (and the other way around as well). 
>>>>> This is realized by storing proxied Java objects on the Java side 
>>>>> in a Map ("registry") and using a common (unique) string value as 
>>>>> the key.
>>>>>
>>>>> So when the Rexx side invokes a Java method, briefly the following 
>>>>> steps take place (there is much more to this, but not important in 
>>>>> this context):
>>>>>
>>>>>   * the Rexx side uses JNI and supplies the string identifying the
>>>>>     Java object in the Map, the method name in uppercase
>>>>>     (caselessness is realized in Rexx by uppercasing all Rexx
>>>>>     tokens outside of quotes) and the arguments, if any,
>>>>>
>>>>>   * the Java side fetches the Java object from the Java registry
>>>>>     and inspects it for its available methods, picks those that
>>>>>     have caselessly the same name as the supplied method name,
>>>>>     then checks whether the arguments are type-compatible and
>>>>>     invokes the method; any returned Java object will be placed in
>>>>>     the Java "registry" and its key (a unique string) is returned
>>>>>     to Rexx.
>>>>>
>>>>
>>>> Couldn't you save also the method's return type besides the result 
>>>> under the same key into the registry, so next time you have to 
>>>> invoke a method on such object, you retrive the object and the type 
>>>> you use to find methods on?
>>>>
>>>>> So after returning control to Rexx, there is no information 
>>>>> available about the Java object in the Java registry other than 
>>>>> the string serving as the key to fetch that Java object on the 
>>>>> Java side.
>>>>>
>>>>
>>>> Not on the Rexx side, but on the Java side in the registry. Right 
>>>> where you need it, right?
>>>>
>>>>> Take this Rexx code as an example (the tilde is the message 
>>>>> operator in ooRexx and can have white space around it):
>>>>>
>>>>>     clzToolkit = bsf.import("java.awt.Toolkit")
>>>>>     dim = clzToolkit ~getDefaultToolkit ~getScreenSize
>>>>>
>>>>> will be transformed internally by Rexx into:
>>>>>
>>>>>     CLZTOOLKIT=BSF.IMPORT("java.awt.Toolkit")
>>>>>     DIM=CLZTOOLKIT~GETDEFAULTTOOLKIT~GETSCREENSIZE
>>>>>
>>>>> and the Java bridge gets used (via JNI) as follows:
>>>>>
>>>>>   * step 1: BSF.IMPORT() is an external Rexx function that will
>>>>>     use JNI and cause a Java class object to be loaded (and stored
>>>>>     in the Java registry) and boxed as an ooRexx proxy class
>>>>>     object upon return and assigned to the Rexx variable CLZTOOLKIT,
>>>>>
>>>>
>>>> This time the 'type' to search methods on is the same as the class 
>>>> object you just "imported".
>>>>
>>>>>  *
>>>>>
>>>>>
>>>>>   * step 2: the CLZTOOLKIT~GETDEFAULTTOOLKIT statement contains a
>>>>>     Rexx message that will cause JNI to be used and the Java
>>>>>     method GETDEFAULTTOOLKIT to be executed for the Java object
>>>>>     referenced by CLZTOOLKIT (which incorporates the unique string
>>>>>     for that proxied Java class object); the returned Java object
>>>>>     will be stored in the Java registry, its unique key (a string)
>>>>>     returned, boxed as an ooRexx proxy object value which will be
>>>>>     the receiver of the next Rexx message,
>>>>>
>>>>
>>>> Right and if you also save the return type of the method you just 
>>>> called into the registry besides the returned object on the Java 
>>>> side, you can use it later...
>>>>
>>>>>  *
>>>>>
>>>>>
>>>>>   * step 3: the returned value gets the GETSCREENSIZE Rexx message
>>>>>     sent to it causing JNI to be used and the Java method
>>>>>     GETSCREENSIZE to be located and executed for the Java object
>>>>>     returned from the previous step;
>>>>>
>>>>
>>>> The method should then use the saved method return type from 
>>>> previous step for looking up the GETSCREENSIZE method...
>>>>
>>>>>   * the returned Java object will be stored in the Java registry,
>>>>>     its unique key (a string) returned, boxed as an ooRexx proxy
>>>>>     object value that gets assigned to the Rexx variable DIM.
>>>>>
>>>>
>>>> You should then store the getScreenSize() method's return type 
>>>> besides the returned object under the key... You see the pattern?
>>>>
>>>>>  *
>>>>>
>>>>>
>>>>> Each step gets carried out contextless, i.e. there is no Java 
>>>>> context available, that we (or the Java compiler) can see/infer 
>>>>> when looking at a Java program.
>>>>>
>>>>
>>>> When you invoke them method you not only store the returned object 
>>>> but also the method's return type.
>>>>
>>>>
>>>> If you need casting, then this would need to be explicit (like in 
>>>> Java).
>>>>
>>>> There's one problem with this scheme. What is the key you use to 
>>>> register returned object? Is it based on object identity? When 
>>>> methods return the same instance, is it saved under the same key? 
>>>> If yes, which is understandable, then there might be a problem when 
>>>> two methods with different return types return the same instance. 
>>>> Which return type should you use to find methods for following 
>>>> invocations then? Maybe the most specific type (if they are 
>>>> related) or both (all) of them if they are not and then use them 
>>>> all to search for methods.
>>>>
>>>> Regards, Peter
>>>>
>>>>> ---rony
>>>>>
>>>>> P.S.: Also it might be interesting to know, that with that same 
>>>>> Rexx-Java bridge it is possible to implement Java methods from 
>>>>> interface or abstract classes in Rexx! In that case there is a 
>>>>> Java proxy class available for proxying Rexx objects and on the 
>>>>> Rexx side there is a Rexx Directory to maintain the proxied Rexx 
>>>>> objects for their Java proxies. Fun stuff! :)
>>>>>
>>>>>
>>>>>
>>>>> On 06.01.2017 23:22, Peter Levart wrote:
>>>>>> Hi Rony,
>>>>>>
>>>>>> On 01/06/2017 02:28 PM, Rony G. Flatscher wrote:
>>>>>>>> >The j.l.r.Method object on which you call invoke() should not be obtained by inspecting the
>>>>>>>> >methods of the implementation class given by getDefaultToolkit().getClass(). Implementation
>>>>>>>> >classes (i.e. classes in non-exported packages) cannot be instantiated, nor their members
>>>>>>>> >manipulated, by code outside their module.
>>>>>>>> >
>>>>>>>> >The j.l.r.Method object on which you call invoke() should be obtained by inspecting the methods of
>>>>>>>> >the "public Java class" java.awt.Toolkit. The first argument that you pass to invoke(), indicating
>>>>>>>> >the receiver, can still be instanceof the implementation class.
>>>>>>> As was noted earlier, the information that some Java object xyz was created by some public method
>>>>>>> "getDefaultToolkit()" and hence knowing that its return type would be that of the java.desktop
>>>>>>> public class java.awt.Toolkit is not available at runtime.
>>>>>>
>>>>>> But it is. The method Toolkit.getDefaultToolkit() has a return 
>>>>>> type. You can use reflection to find out that return type of that 
>>>>>> method:
>>>>>>
>>>>>> Method getDefKitMeth = Toolkit.class.getMethod("getDefaultToolkit");
>>>>>> Class<?> tkClass = getDefKitMeth.getReturnType();
>>>>>>
>>>>>> // now you can obtain the toolkit instance:
>>>>>> Object tkInst = getDefKitMeth.invoke(null);
>>>>>>
>>>>>> // and obtain a method to be called upon it
>>>>>> Method getScrSizMeth = tkClass.getMethod("getScreenSize");
>>>>>>
>>>>>> // and invoke it:
>>>>>> Object screenSize = getScrSizMeth.invoke(tkInst);
>>>>>>
>>>>>> ... and so on...
>>>>>>
>>>>>>
>>>>>> You see, I never had to mention java.awt.Toolkit type explicitly 
>>>>>> to invoke getScreenSize on an object of that type (or subtype). 
>>>>>> If you think what a programmer does when he codes this in 
>>>>>> straight Java without using reflection, it is the following:
>>>>>>
>>>>>> 1. He finds out a factory method on Toolkit class: 
>>>>>> Toolkit.getDefaultToolkit()
>>>>>> 2. He looks up the return type of that method (in javadocs).
>>>>>> 3. He uses that type to declare a local variable to which it 
>>>>>> assigns the result of the method invocation:
>>>>>>
>>>>>> java.awt.Toolkit tkInst = java.awt.Toolkit.getDefaultToolkit();
>>>>>>
>>>>>> 4. He looks up and finds an instance method to call in type 
>>>>>> java.awt.Toolkit: java.awt.Toolkit.getScreenSize() and writes it 
>>>>>> down:
>>>>>>
>>>>>> tkInst.getScreenSize();
>>>>>>
>>>>>> Above invocation is using static type java.awt.Toolkit - the 
>>>>>> return type of Toolkit.getDefaultToolkit().
>>>>>>
>>>>>> You can do similar things with reflection. Instead of using 
>>>>>> anInstance.getClass() to get the runtime class of the instance, 
>>>>>> you can use Method.getReturnType() of the method that was used to 
>>>>>> obtain the instance. If API is designed so that no casts are 
>>>>>> needed when you chain calls, then this should work.
>>>>>>
>>>>>>
>>>>>> Regards, Peter
>>>
>>
>



More information about the jigsaw-dev mailing list