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

Rony G. Flatscher Rony.Flatscher at wu.ac.at
Sat Jan 7 18:13:44 UTC 2017


Forgot to supply a reflective version for my sample classes, so for completeness here the reflective
version E:

    class E
    {
        public static void main (String args[]) throws Exception
        {
            System.out.println("E: java.version="+System.getProperty("java.version"));
            System.out.println("E: B.getInstance(), instantiating private class, invoking A methods
    ...");
            A a=B.getInstance();
            System.out.println("E: a="+a);

            Class aClz=a.getClass();
            System.out.println("E: a.getClass()="+aClz);

                // a.hi();
            java.lang.reflect.Method m = aClz.getMethod("hi");
            System.out.println("E: Method \"hi()\": m.getDeclaringClass()="+m.getDeclaringClass());
            m.invoke(a);

                // a.there();
            m = aClz.getMethod("there");
            System.out.println("E: Method \"there()\": m.getDeclaringClass()="+m.getDeclaringClass());
            m.invoke(a);
        }
    }

Running it yields:

    F:\tmp\java\reflective\case_02>java E
    E: java.version=1.8.0_111
    E: B.getInstance(), instantiating private class, invoking A methods ...
    E: a=B$C at 10dea4e
    E: a.getClass()=class B$C
    E: Method "hi()": m.getDeclaringClass()=class A
    A: hi
    E: Method "there()": m.getDeclaringClass()=class B$C
    C: there

---rony


On 06.01.2017 14:28, Rony G. Flatscher wrote:
> On 05.01.2017 23:31, Alex Buckley wrote:
>> On 1/5/2017 1:16 PM, Rony G. Flatscher wrote:
>>> 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.
>> 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.
>
> ---
>
> It is totally o.k. if one is not able to instantiate a public class from a module that is closed to
> oneself.
>
> The situation here is different though: the reflective code does not instantiate any class from the
> closed module. Instead getDefaultToolkit() which is able to access that module is doing that and
> returning the created instance. The reflective code ought to be able to access/invoke any public
> members in that returned object if they belong to a public, accessible class which is the case for
> java.awt.Toolkit residing in java.desktop.
>
> It seems that this situation is comparable to the following "classic" Java scenario:
>
>   * some abstract class A implements a public method "hi" and a public abstract method "there"
>   * some class B implements a static private inner class C that extends A and implements "there" and
>     a static method getInstance() the instantiates C and returns it cast to A
>       o the main method of B is able to instantiate C and use all of its methods, as well as using
>         getInstance() and using all A methods via/on it
>   * some class D uses B.getInstance() and receives an object that in fact is an instance of the
>     private class B.C, yet it is able to use its method "there"
>       o so invoking public methods in private classes is possible under these circumstances
>       o java.lang.reflect can be safely employed under these circumstances
>
> Here a sample of these classes:
>
>     --- cut here ---
>     public abstract class A
>     {
>         public void hi()
>         {
>             System.out.println("A: hi");
>         }
>
>         abstract public void there();
>     }
>
>     --- cut here ---
>     class B
>     {
>         public static void main (String args[])
>         {
>             System.out.println("B: new C(), instantiatign private class, invoking A and C methods...");
>             C c=new C();
>             System.out.println("B: c="+c);
>             c.hi();
>             c.there();
>             c.thisIsIt();
>
>             System.out.println("B: B.getInstance(), instantiating private class, invoking A methods
>     ...");
>             A a=getInstance();
>             System.out.println("B: a="+a);
>             a.hi();
>             a.there();
>         }
>
>         static public A getInstance()
>         {
>             return (A) new C();
>         }
>
>         static private class C extends A
>         {
>             public void there()
>             {
>                 System.out.println("C: there");
>             }
>
>             private void thisIsIt()
>             {
>                 System.out.println("C: this is it!");
>             }
>         }
>     }
>
>     --- cut here ---
>     class D
>     {
>         public static void main (String args[])
>         {
>             System.out.println("D: B.getInstance(), instantiating private class, invoking A methods
>     ...");
>             A a=B.getInstance();
>             System.out.println("D: a="+a);
>             a.hi();
>             a.there();
>         }
>     }
>
> Compiling the above three classes and then runnint B and D yields:
>
>     F:\tmp\java\case_02>javac *.java
>
>     F:\tmp\java\case_02>java B
>     B: new C(), instantiatign private class, invoking A and C methods...
>     B: c=B$C at 19e0bfd
>     A: hi
>     C: there
>     C: this is it!
>     B: B.getInstance(), instantiating private class, invoking A methods ...
>     B: a=B$C at 139a55
>     A: hi
>     C: there
>
>     F:\tmp\java\case_02>java D
>     D: B.getInstance(), instantiating private class, invoking A methods ...
>     D: a=B$C at 19e0bfd
>     A: hi
>     C: there
>
> This is the interactive Rexx code (the tilde is the message operator) where one enters statements
> that get interpreted line by line (after hitting enter):
>
>     F:\tmp\java\case_02>rexxtry
>     REXX-ooRexx_5.0.0(MT)_32-bit 6.05 7 Aug 2016
>       rexxtry.rex lets you interactively try REXX statements.
>         Each string is executed when you hit Enter.
>         Enter 'call tell' for a description of the features.
>       Go on - try a few...            Enter 'exit' to end.
>     call bsf.cls            -- get the Rexx-Java bridge
>       ........................................... rexxtry.rex on WindowsNT
>     clz=bsf.import("B")
>       ........................................... rexxtry.rex on WindowsNT
>     o=clz~getInstance
>       ........................................... rexxtry.rex on WindowsNT
>     say o
>     B$C at 14c966a
>       ........................................... rexxtry.rex on WindowsNT
>     o~hi
>     A: hi
>       ........................................... rexxtry.rex on WindowsNT
>     o~there
>     C: there
>       ........................................... rexxtry.rex on WindowsNT
>
> As you can see it is possible and safe to execute the public method "there" in the private class B.C
> using plain java.lang.reflect.
>
> The situation with the module system should be comparable: although one is not able to use public
> classes of closed modules to create instances, others may be able to do so. If they return an
> instance from a public class of a closed module all public members should be accessible/invocable
> that are defined in an accessible public class that that object's class implements.
>
>>> (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.)
>> Nope, because access to members is gated by access to the enclosing class. If the enclosing class
>> is inaccessible then its members are inaccessible.
> Sure, that's the way it is. However, if the class of the object (retrieved via some public member of
> a public accessible class that has access to that module) in the closed module is defined to be
> public itself, then why would it be regarded to be too risky to allow access to all of its public
> members in that situation?
>
> ---rony



More information about the jigsaw-dev mailing list