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

Rony G. Flatscher Rony.Flatscher at wu.ac.at
Thu Jan 5 21:16:29 UTC 2017


On 05.01.2017 21:07, Phil Race wrote:
> Sort of .. it depends whether you could use getDeclaredMethod instead.
>
> One question I have is, how would you update the code if you
> were given the instance "foo", and need to programmatically
> work out what is the correct super-type of Foo that exports
> the interface method "bar" ?
That is exactly the problem. The entire system works on reflection (and has so since Java 1.2!).

The reflective code gets some Java object (actually a unique string serving as the key into a Map
which will be used to retrieve the referenced Java object), usually a (uppercased) string denoting
the method (no way to supply the correct spelling as the script language translates all tokens
outside of quotes into uppercase) and a list of values serving as arguments. The reflective code
must now infer which method can be picked and reflectively invoke it.

Omitting details: a getClass() is used for getting the class object and getMethods() to fetch the
methods and then use Method.invoke(...) for the matching Method.
[Besides, there is partly a library in use that was originally created with Java 1.1.]

> i.e you don't have the string "java.awt.Toolkit" handy and need to infer it from the instance class.
Indeed.

---

The rule for using the Java bridge for the Rexx programmers has always been very simple: you are
only allowed to use public Java classes, public Java fields and public Java methods as these are
guaranteed to be available to everyone at all times.

This is what happens in this case too: the public Java class java.awt.Toolkit gets loaded, its
public class method getDefaultToolkit() gets invoked and a java.awt.Toolkit object gets returned by
that method.

The returned Toolkit object is known from the documentation to allow access to all documented public
methods, so its class (or one of its superclasses) must have the public abstract method
getScreenDimension() implemented (being a subclass of java.awt.Toolkit it must implement all
abstract members otherwise no instance could be created from it), therefore getting that Method
object and invoking it.

There has been no reason since the beginning of Java to know from a programmer's point of view how
the implementation of the class took place for the returned object (e.g. which package serves as its
home) as long as it was a subclass of that public Java class and as long as we have adhered to its
its public members only. (Also, I would expect to be able to access any additional public members of
such a subclass, irrespectible of its implementation, just from knowing that in Java one can always
access public classes and public members.)

Everything has been merely based (and restricted) to public Java classes and its public members and
has worked on all Java versions at least since 2000/01 (starting out with OS/2 and Windows back then).

---rony


>
> On 01/05/2017 12:01 PM, Remi Forax wrote:
>> Phil,
>> This is not a new problem per se, you already had this "bug" if the returned class at runtime was
>> a class not declared public,
>> it's just more visible in the modular world of Java 9 because to be accessible a class has to be
>> declared public *and* the package has to be exported.
>>
>> cheers,
>> Rémi
>>
>> ----- Mail original -----
>>> De: "Phil Race" <philip.race at oracle.com>
>>> À: "Alex Buckley" <alex.buckley at oracle.com>, jigsaw-dev at openjdk.java.net, "Rony G. Flatscher"
>>> <Rony.Flatscher at wu.ac.at>
>>> Envoyé: Jeudi 5 Janvier 2017 20:45:56
>>> Objet: Re: Using java.awt.Toolkit.getDefaultToolkit().getScreenSize()    reflectively causes
>>> InaccessibleObjectException
>>> ah yes .. I can see how one might code that way.
>>> I don't know how common a problem this is, but
>>> such code will need to be updated.
>>>
>>> ----
>>> import java.awt.Toolkit;
>>>
>>> public class TK8 {
>>>      public static void main(String args[]) throws Exception {
>>>         Toolkit tk = Toolkit.getDefaultToolkit();
>>>         Class tkc = tk.getClass();
>>>         System.out.println(tkc);
>>>         java.lang.reflect.Method m = tkc.getMethod("getScreenSize");
>>>         System.out.println(m.invoke(tk));
>>>      }
>>> }
>>>
>>> ~/jdk8u45/bin/java TK8
>>> class sun.awt.X11.XToolkit
>>> java.awt.Dimension[width=1920,height=1200]
>>>
>>> ~/jdk9b142/bin/java TK8
>>> class sun.awt.X11.XToolkit
>>> Exception in thread "main" java.lang.NoSuchMethodException:
>>> sun.awt.X11.XToolkit.getScreenSize()
>>>      at java.lang.Class.getDeclaredMethod(java.base at 9-ea/Class.java:2318)
>>>      at TK8.main(TK8.java:8)
>>> ----
>>>
>>> -phil.
>>>
>>> On 01/05/2017 11:34 AM, Alex Buckley wrote:
>>>> Rony mentioned "the returned Toolkit is of type sun.awt.X11.XToolkit"
>>>> which suggests that he is calling getClass() on the result of
>>>> getDefaultToolkit(), and then reflecting further on that Class object
>>>> and its Methods. As has been discussed previously on jigsaw-dev, this
>>>> won't work for implementation classes; it's necessary to reflect over
>>>> exported classes and interfaces instead.
>>>>
>>>> Alex
>>>>
>>>> On 1/5/2017 11:22 AM, Phil Race wrote:
>>>>> This should be discussed on jigsaw-dev.
>>>>>
>>>>> But can you share your code ? -  since the following works for me :
>>>>>
>>>>> import java.awt.Toolkit;
>>>>>
>>>>> public class TK {
>>>>>       public static void main(String args[]) throws Exception {
>>>>>          Toolkit tk = Toolkit.getDefaultToolkit();
>>>>>          Class tkc = Class.forName("java.awt.Toolkit");
>>>>>          java.lang.reflect.Method m = tkc.getMethod("getScreenSize");
>>>>>          System.out.println(m.invoke(tk));
>>>>>       }
>>>>> }
>>>>>
>>>>> ~/jdk9b142/bin/java TK
>>>>> java.awt.Dimension[width=1920,height=1200]
>>>>>
>>>>> -phil.
>>>>>
>>>>> On 01/05/2017 11:03 AM, Rony G. Flatscher wrote:
>>>>>> Experimenting with further scripts indicates that this is a systematic
>>>>>> problem whenever the official
>>>>>> APIs return members that are not made available to an unnamed module:
>>>>>> e.g. JavaFX some
>>>>>> "com.sun.javafx.collections.VetoableListDecorator" or in a "plain"
>>>>>> awt/swing app some
>>>>>> "sun.java2d.SungGraphics2D".
>>>>>>
>>>>>> ---rony
>>>>>>
>>>>>> On 05.01.2017 19:42, Rony G. Flatscher wrote:
>>>>>>> Trying to run a program that gets the screen dimensions using
>>>>>>> java.awt.Toolkit.getDefaultToolkit().getScreenSize() reflectively.
>>>>>>>
>>>>>>> On a 64-bit Ubuntu the returned Toolkit is of type
>>>>>>> sun.awt.X11.XToolkit. Reflectively invoking its
>>>>>>> method getScreenSize() causes the following exception to be thrown on
>>>>>>> 9-ea+134:
>>>>>>>
>>>>>>>       java.lang.reflect.InaccessibleObjectException: unable to make
>>>>>>> member of class sun.awt.SunToolkit
>>>>>>>       accessible: module java.desktop does not export sun.awt to
>>>>>>> unnamed module ...
>>>>>>>
>>>>>>> A little bit baffled as this is from a script that has been working
>>>>>>> flawlessly throughout more than
>>>>>>> a decade on various Java versions and which employs documented public
>>>>>>> methods only (the sun.awt
>>>>>>> object is returned by java.awt.Toolkit). Is this a known
>>>>>>> "legacy"problem :) that I could circumvent
>>>>>>> somehow or a bug that needs to be reported?
>>>>>>>
>>>>>>> ---rony 



More information about the jigsaw-dev mailing list