Reflection: how can one access public fields (members) in a superclass ?

Rony G. Flatscher Rony.Flatscher at wu.ac.at
Tue Jan 23 18:17:47 UTC 2018


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 at 5afa04c, o.getMyClassName(): via: this=[mtest3.Class03A at 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
>>             {
>>             }
>>
>>     --------------------------------------------------------------------------



More information about the jigsaw-dev mailing list