Using java.awt.Toolkit.getDefaultToolkit().getScreenSize() reflectively causes InaccessibleObjectException
Rony G. Flatscher
Rony.Flatscher at wu.ac.at
Fri Jan 6 13:28:57 UTC 2017
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>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