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