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