As it does not make sense to supply my current "under construction" code, I created two Java programs, one using reflection and one MethodHandles that behave like my current testbed. I added those two Java programs "TestUseViaReflection.java" (compile and run with "7a_module_compile_and_run_TestUseViaReflection.cmd") and "TestUseViaReflectionAndMethodHandles.java" (compile and run with "8a_module_compile_and_run_TestUseViaReflectionAndMethodHandles.cmd") to the zip archive and replaced the zip-archive on Dropbox (<https://www.dropbox.com/s/fti7camrb5hs7we/02-20180123-getPublicField.zip?dl=0>) with the updated one.
This is the "pure reflection" version, that I would prefer, "TestUseViaReflection.java": import java.lang.reflect.Field; public class TestUseViaReflection { public static void main (String args[]) { mtest3.Class03A o=new mtest3.Class03A(); Class sc =o.getClass().getSuperclass(); // get superclass mtest2.Class02A Field field = null; try { field =sc.getDeclaredField("pubStaticFromClass02A"); // get static field } catch (Exception e) { System.err.println("exception thrown in sc.getDeclaredField(...): "+e); e.printStackTrace(); System.exit(-1); } Object result=null; try { result=field.get(o); // get field's value } catch (Exception e) { System.err.println("exception thrown in field.get(...): "+e); e.printStackTrace(); System.exit(-1); } System.out.println("o.pubStaticFromClass02A : "+result ); } } Running it yields: G:\xfer\java9modules\02-20180123-getPublicField>java -cp "." --module-path out --add-modules mod_A,mod_B,mod_C TestUseViaReflection exception thrown in field.get(...): java.lang.IllegalAccessException: class TestUseViaReflection cannot access class mtest2.Class02A (in module mod_B) because module mod_B does not export mtest2 to unnamed module @4e04a765 java.lang.IllegalAccessException: class TestUseViaReflection cannot access class mtest2.Class02A (in module mod_B) because module mod_B does not export mtest2 to unnamed module @4e04a765 at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:361) at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:589) at java.base/java.lang.reflect.Field.checkAccess(Field.java:1075) at java.base/java.lang.reflect.Field.get(Field.java:416) at TestUseViaReflection.main(TestUseViaReflection.java:23) ---------------- This is the version that tries to use MethodHandles instead, "TestUseViaReflectionAndMethodHandles.java": import java.lang.reflect.Field; import java.lang.invoke.*; public class TestUseViaReflectionAndMethodHandles { public static MethodHandles.Lookup lookup=MethodHandles.lookup(); public static void main (String args[]) { mtest3.Class03A o=new mtest3.Class03A(); Class sc =o.getClass().getSuperclass(); // get superclass mtest2.Class02A Field field = null; try { field =sc.getDeclaredField("pubStaticFromClass02A"); // get static field } catch (Exception e) { System.err.println("--> exception thrown in sc.getDeclaredField(...): "+e); e.printStackTrace(); System.exit(-1); } Object result=null; MethodHandle mh; try { mh=lookup.unreflectGetter(field); result=mh.invoke(o); } catch (Throwable t) { System.err.println("--> exception thrown in field.get(...): "+t); t.printStackTrace(); System.exit(-1); } System.out.println("o.pubStaticFromClass02A : "+result ); } } Running it yields: G:\xfer\java9modules\02-20180123-getPublicField>java -cp "." --module-path out --add-modules mod_A,mod_B,mod_C TestUseViaReflectionAndMethodHandles --> exception thrown in field.get(...): java.lang.IllegalAccessException: access to public member failed: mtest2.Class02A.pubStaticFromClass02A/java.lang.String/getStatic, from TestUseViaReflectionAndMethodHandles (unnamed module @4e04a765) java.lang.IllegalAccessException: access to public member failed: mtest2.Class02A.pubStaticFromClass02A/java.lang.String/getStatic, from TestUseViaReflectionAndMethodHandles (unnamed module @4e04a765) at java.base/java.lang.invoke.MemberName.makeAccessException(MemberName.java:914) at java.base/java.lang.invoke.MethodHandles$Lookup.checkAccess(MethodHandles.java:2193) at java.base/java.lang.invoke.MethodHandles$Lookup.checkField(MethodHandles.java:2143) at java.base/java.lang.invoke.MethodHandles$Lookup.getDirectFieldCommon(MethodHandles.java:2355) at java.base/java.lang.invoke.MethodHandles$Lookup.getDirectFieldNoSecurityManager(MethodHandles.java:2350) at java.base/java.lang.invoke.MethodHandles$Lookup.unreflectField(MethodHandles.java:1863) at java.base/java.lang.invoke.MethodHandles$Lookup.unreflectGetter(MethodHandles.java:1854) at TestUseViaReflectionAndMethodHandles.main(TestUseViaReflectionAndMethodHandles.java:27) ---------------- However the Java program "TestUse_mtest3_Class03A.java" compiles and runs successfully: Compiling the modules and then using them in the following Java program (via the CLASSPATH) works, here the source: TestUse_mtest3_Class03A.java public class TestUse_mtest3_Class03A { public static void main (String args[]) { mtest3.Class03A o=new mtest3.Class03A(); System.out.println("o.pubStaticFromClass02A : "+o.pubStaticFromClass02A ); System.out.println("o.pubFromClass02A : "+o.pubFromClass02A ); System.out.println("o: "+o+", o.getMyClassName(): "+o.getMyClassName()); } } Compiling the above program and running it yields: o.pubStaticFromClass02A : static-mtest2.Class02A o.pubFromClass02A : instance-mtest2.Class02A o: mtest3.Class03A@5afa04c, o.getMyClassName(): via: this=[mtest3.Class03A@5afa04c], getMyClassName()=[class-mtest1.Class01A] ---------------- Maybe I miss something obvious. ---rony On 23.01.2018 19:17, Rony G. Flatscher wrote: > Was asked off-line for a zip-archive for convenience, hence I created a zip > archive and put it on > Dropbox. Here the link to get the zip-archive: > <https://www.dropbox.com/s/fti7camrb5hs7we/02-20180123-getPublicField.zip?dl=0>. > Just unzip, go > into the <02-20180123-getPublicField> directory and run (on Windows) > "1_compile.cmd", then either > "5a_module_compile_and_run_TestUse_mtest3_Class03A.cmd" or > "5b_classpath_compile_and_run_TestUse_mtest3_Class03A.cmd". Adapting the > scripts to Unix should be > straight forward. > > Being formally an OpenJDK contributor there should be no legal problems. > > ---rony > > > On 23.01.2018 18:32, Rony G. Flatscher wrote: >> Oh, forgot the scripts to compile and run (these are under Windows): >> >> Assuming that the sources of "mod_A", "mod_B" and m"od_C" are located in >> "src", the compilation >> result should be placed into "out" here the compile script: >> >> rd out /s /q && md out >> >> @echo compiling module mod_A >> dir src\mod_A\*java /s /b > mod_A_source_files.txt >> type mod_A_source_files.txt >> javac -d out\mod_A @mod_A_source_files.txt >> >> @echo compiling module mod_B >> dir src\mod_B\*java /s /b > mod_B_source_files.txt >> type mod_B_source_files.txt >> javac --module-path out -d out\mod_B @mod_B_source_files.txt >> >> @echo compiling module mod_C >> dir src\mod_C\*java /s /b > mod_C_source_files.txt >> type mod_C_source_files.txt >> javac --module-path out -d out\mod_C @mod_C_source_files.txt >> >> Assuming that "TestUse_mtest3_Class03A.java" is located in the directory >> that contains the "out" >> subdirectory: >> >> del TestUse_mtest3_Class03A.class >> javac -cp "." --module-path out --add-modules mod_A,mod_B,mod_C >> TestUse_mtest3_Class03A.java >> >> java -cp "." --module-path out --add-modules mod_A,mod_B,mod_C >> TestUse_mtest3_Class03A >> >> ---rony >> >> >> On 23.01.2018 15:52, Rony G. Flatscher wrote: >>> Given three modules (sources at the end) where >>> >>> * "mod_A" exports its package "mtest1", to everyone >>> * "mod_B" requires "mod_A" and exports its package "mtest2" to "mod_C" >>> * "mod_C" requires "mod_B" and exports its package "mtest3" to everyone >>> >>> "mod_B"'s class "mtest2.Class02A" defines two public fields, one static >>> ("pubStaticFromClass02A") >>> and one an instance ("pubFromClass02") one. >>> >>> Compiling the modules and then using them in the following Java program >>> (via the CLASSPATH) works, >>> here the source: >>> >>> TestUse_mtest3_Class03A.java >>> >>> public class TestUse_mtest3_Class03A >>> { >>> public static void main (String args[]) { >>> mtest3.Class03A o=new mtest3.Class03A(); >>> System.out.println("o.pubStaticFromClass02A : >>> "+o.pubStaticFromClass02A ); >>> System.out.println("o.pubFromClass02A : >>> "+o.pubFromClass02A ); >>> System.out.println("o: "+o+", o.getMyClassName(): >>> "+o.getMyClassName()); >>> } >>> } >>> >>> Compiling the above program and running it yields: >>> >>> o.pubStaticFromClass02A : static-mtest2.Class02A >>> o.pubFromClass02A : instance-mtest2.Class02A >>> o: mtest3.Class03A@5afa04c, o.getMyClassName(): via: >>> this=[mtest3.Class03A@5afa04c], >>> getMyClassName()=[class-mtest1.Class01A] >>> >>> Here is a 1:1 transcription from the above Java program to Rexx which uses >>> Java reflection to >>> achieve the same: >>> >>> test.rex >>> >>> o=.bsf~new("mtest3.Class03A") -- create Java object >>> say "o~pubStaticFromClass01A:" o~pubStaticFromClass02A >>> say "o~pubFromClass01A :" o~pubFromClass02A >>> say "o:" o "o~getMyClassName:" o~getMyClassName >>> >>> ::requires BSF.CLS -- direct interpreter to load Java bridge >>> >>> Running the Rexx program yields the following reflection error: >>> >>> // // -> -> RexxReflectJava9.processField(): EXCEPTION in GET-operation: >>> tmpField="pubStaticFromClass02A" exception: >>> "java.lang.IllegalAccessException: class >>> org.rexxla.bsf.engines.rexx.RexxReflectJava9 cannot access class >>> mtest2.Class02A (in module >>> mod_B) because module mod_B does not export mtest2 to unnamed module >>> @51c8530f" >>> >>> The reflection code currently >>> >>> * gets the type from the Java object ("mtest3.Class03A") and tests >>> whether the package "mtest3" is >>> exported (it is), >>> * looks for all declaredFields and finds none, so it gets the superclass >>> "mtest2.Class02A", >>> * looks for all declaredFields and locates the Field named >>> "pubStaticFromClass02A" and invokes the >>> Field's get method, supplying the Java object (an instance of class >>> mtest3.Class03A) which >>> causes an IlleagalAccessException. >>> >>> Although it is true that "mod_B" is not exported to the unnamed module it >>> is still the case that >>> "mod_C" is exported (and class "mtest3.Class03A" can be accessed), such >>> that all public members in >>> its superclasses should be accessible via reflection, even in the case that >>> a public member resides >>> in a module that is not exported to the reflector from the unnamed module? >>> >>> The reflective code would be able to assess that the supplied object is >>> from an exported type and >>> hence allow the get access in this case for reflected members in its >>> superclasses, like it seems the >>> Java compiler allows for. >>> >>> ---rony >>> >>> Here are the contents of the module directories in source: >>> >>> >>> --------------------------------------------------------------------------- >>> >>> mod_A/module-info.java >>> >>> module mod_A { exports mtest1; } >>> >>> mod_A/mtest1/Class01A.java >>> >>> package mtest1; >>> >>> abstract public class Class01A >>> { >>> protected static String myClassName = >>> "class-mtest1.Class01A"; >>> } >>> >>> >>> --------------------------------------------------------------------------- >>> >>> mod_B/module-info.java >>> >>> module mod_B { >>> requires mod_A; >>> exports mtest2 to mod_C; >>> } >>> >>> mod_B/mtest2/Class02A.java >>> >>> package mtest2; >>> >>> public class Class02A extends mtest1.Class01A >>> { >>> public static String >>> pubStaticFromClass02A="static-mtest2.Class02A"; >>> public String pubFromClass02A >>> ="instance-mtest2.Class02A"; >>> >>> public String getMyClassName() >>> { >>> return "via: this=["+this+"], >>> getMyClassName()=["+myClassName+"]"; >>> } >>> } >>> >>> >>> --------------------------------------------------------------------------- >>> >>> mod_C/module-info.java >>> >>> module mod_B { >>> requires mod_A; >>> exports mtest2 to mod_C; >>> } >>> >>> mod_C/mtest3/Class03A.java >>> >>> package mtest3; >>> >>> public class Class03A extends mtest2.Class02A >>> { >>> } >>> >>> >>> --------------------------------------------------------------------------