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@19e0bfd
A: hi
C: there
C: this is it!
B: B.getInstance(), instantiating private class, invoking A methods ...
B: a=B$C@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@19e0bfd
A: hi
C: there
C: this is it!
B: B.getInstance(), instantiating private class, invoking A methods ...
B: a=B$C@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@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@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