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@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@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

Reply via email to