Reflection: how does one access a protected member in a superclass reflectively?

Rony G. Flatscher Rony.Flatscher at wu.ac.at
Mon Jan 15 20:56:51 UTC 2018


Finally having gained enough time to start rewriting the reflection part for a bridge between a
scripting language (ooRexx) and Java 9.

>From past discussions on this list my view upon accessing members in superclasses that are protected
in Java 9 is possible as such protected members are regarded to be public (they are accessible) from
their subclasses.

To test against the new module system I have created three simple modules (only what is relevant to
this problem is given):

  * "mod_A": defines a package "mtest1" with an abstract public class "Class01A" that implements an
    interface "I01A", its "module-info.java" reads:
            "module mod_A { exports mtest1; }"

  * "mod_B": defines a package "mtest2" with a public "Class02A" which extends "mtest1.Class01A" and
    implements an interface "I02A" which extends "mtest1.I01A", its "module-info.java" reads:
            "module mod_B {  requires mod_A;     exports mtest2 to mod_C;  }

  * "mod_C": defines a package "mtest2" with a public "Class03A" which extends "mtest2.Class02A",
    its "module-info.java" reads:
    "module mod_C { exports mtest3; requires mod_B; }"

The code doing the reflection resides in the unnamed module for the time being (it eventually will
be part of a module).

Running the script code is done against the following Java settings:

    -cp "%CLASSPATH%" --module-path F:\java9modules\out --add-modules mod_A,mod_B,mod_C

In the first round reflecting Fields is used as a testbed. The reflection code at this stage is able
to successfully skip over the closed "mod_B" module and arrive at "mod_A" classes. However,
reflecting for "Class03A" instance is not able to access the defined *protected* static field
"myClassName" in the superclass "Class01A" (the String value of that static field is:
"class-mtest1.Class01A")!

The debug output with the trailing stack trace for the runtime error is:

    about to load class [mtest3.Class03A]
             loaded, clz~toString: [class mtest3.Class03A]
             [java.lang.Class at 4973813a] package: [package mtest3] module: [module mod_C]
    org.rexxla.bsf.engines.rexx.RexxReflectJava9 at 6fb0d3ed -> reflect(rru):
    org.rexxla.bsf.engines.rexx.RexxReflectUtil at 16f7c8c1, field values:
    --->    rajo          =[org.rexxla.bsf.engines.rexx.RexxAndJava at 24a35978]
            invocationType=[GET_FIELD_VALUE]
            reflectionType=[REFLECT_FIELD]
            bStrict       =[false]
            beanName      =[mtest3.Class03A at 1563da5]
            bean          =[mtest3.Class03A at 1563da5] instanceof Class? [false]
            beanClz       =[class mtest3.Class03A]
            memberName    =[MYCLASSNAME]
            rexxArgs[]    =[[Ljava.lang.String;@df27fae], rexxArgs.length   =[3]: [GETFIELDVALUE,
    mtest3.Class03A at 1563da5, MYCLASSNAME]
            tmpRexxArgs[] =[[Ljava.lang.String;@704921a5], tmpRexxArgs.length=[0]: []
            funcArgs[]    =[[Ljava.lang.Object;@727803de], funcArgs.length   =[0]: []
            bReturnJSO    =[false]
            bTryCoercions =[true]
    <---
    \\// RexxReflectJava9.reflectField: (1) in tmpClz.getSuperclass() loop:
    tmpClz=[mtest2.Class02A], BEFORE isExported()
    \\// RexxReflectJava9.reflectField: package of tmpClz not EXPORTED, hence SKIPPING tmpClz:
    [mtest2.Class02A]
    \\// RexxReflectJava9.reflectField: now checking                               --->
    tmpClz=[mtest1.Class01A]
    \\// RexxReflectJava9.reflectField: (1) in tmpClz.getSuperclass() loop:
    tmpClz=[mtest1.Class01A], BEFORE isExported()
    //\\ RexxReflectJava9.reflectField: (2) in tmpClz.getSuperclass() loop:
    tmpClz=[mtest1.Class01A], AFTER  isExported()
    RexxReflectJava9.processField(), arrived: -> [GET_FIELD_VALUE], tmpField=[protected static
    java.lang.String mtest1.Class01A.myClassName]: field=[MYCLASSNAME] in
    object=[mtest3.Class03A at 1563da5]
    RexxReflectJava9.processField(): => [GET_FIELD_VALUE]: found field=[MYCLASSNAME] in
    object=[mtest3.Class03A at 1563da5/mtest3.Class03A at 1563da5]
    oops GET-operation: tmpField "myClassName" caused exception "java.lang.IllegalAccessException:
    class org.rexxla.bsf.engines.rexx.RexxReflectJava9 cannot access a member of class
    mtest1.Class01A (in module mod_A) with modifiers "protected static""
    java.lang.reflect.InaccessibleObjectException: Unable to make field protected static
    java.lang.String mtest1.Class01A.myClassName accessible: module mod_A does not "opens  mtest1"
    to unnamed module @16022d9d
            at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(Unknown Source)
            at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(Unknown Source)
            at java.base/java.lang.reflect.Field.checkCanSetAccessible(Unknown Source)
            at java.base/java.lang.reflect.Field.setAccessible(Unknown Source)
            at org.rexxla.bsf.engines.rexx.RexxReflectJava9.processField(RexxReflectJava9.java:294)
            at org.rexxla.bsf.engines.rexx.RexxReflectJava9.reflectField(RexxReflectJava9.java:113)
            at org.rexxla.bsf.engines.rexx.RexxReflectJava9.reflect(RexxReflectJava9.java:59)
            at org.rexxla.bsf.engines.rexx.RexxAndJava.javaCallBSF(RexxAndJava.java:3247)
            at org.rexxla.bsf.engines.rexx.RexxAndJava.javaCallBSF(RexxAndJava.java:4163)
            at org.rexxla.bsf.engines.rexx.RexxAndJava.jniRexxRunProgram(Native Method)
            at org.rexxla.bsf.engines.rexx.RexxEngine.apply(RexxEngine.java:1153)
            at org.rexxla.bsf.RexxDispatcher.main(RexxDispatcher.java:158)

Doing the comparable operation - accessing a field named "myClassName" in Java code from
"mtest3.Class03a" (in the main method) succeeds!

Here is the output of running "mtest3.Class3A" for comparison:

    F:\java9modules>java --module-path out -m mod_C/mtest3.Class03A
    class mtest3.Class03A.main() ...
           getMyClassNameStatic()=[class-mtest1.Class01A]
           myClassName           =[class-mtest1.Class01A]
           getMyName1()          =[from Class01A (static)]
         o.getMyName2()          =[from Class02A (instance)]
         o.myClassName           =[class-mtest1.Class01A]


So the question is, how can I reflectively access "mtest1.Class01A" static protected field
"myClassName" from "mtest3.Class03a" in Java 9?

The Java code for "mtest1.Class01A" (in "mod_A"), "mtest2.Class02A" (in "mod_B") and
"mtest3.Class03A" (in "mod_C") is given below.

---rony

"mod_A":

    package mtest1;

    abstract public class Class01A implements I01A
    {
        protected static String myClassName = "class-mtest1.Class01A";
        protected static String myName1 = "from Class01A (static)";
        protected String myName2 = "from Class01A (instance)";

         public static void main (String args[]) {
             System.err.println(Class01A.class+".main() ...");
         }

         public static String getMyClassNameStatic() // static method in interface
         {
              return myClassName;
         }

         abstract public String getMyClassName() ; // default method in interface

         static protected String getMyName1()
         {
              return myName1;
         }

         abstract protected String getMyName2();
    }


"mod_B":

    package mtest2;

    public class Class02A extends mtest1.Class01A implements I02A
    {
         public static String myName1 = "from Class02A (static)";
         public String myName2 = "from Class02A (instance)";

    public static void main (String args[]) {
              System.err.println(Class02A.class+".main() ...");

              System.err.println(" getMyClassNameStatic()=["+ getMyClassNameStatic()+"]");
              System.err.println(" getMyName1() =["+ getMyName1() +"]");
              Class02A o=new Class02A();
              System.err.println(" o.getMyName2() =["+o.getMyName2() +"]");
              System.err.println(" o.getMyClassName() =["+o.getMyClassName() +"]");
         }

         public String getMyClassName()
         {
              return myClassName;
         }

         protected String getMyName2()
         {
              return myName2;
         }
    }

"mod_C":

    package mtest3;

    public class Class03A extends mtest2.Class02A
    {
        public static void main (String args[]) {
            System.err.println(Class03A.class+".main() ...");

            System.err.println("       getMyClassNameStatic()=["+  getMyClassNameStatic()+"]");
            System.err.println("       myClassName           =["+  myClassName           +"]");
            System.err.println("       getMyName1()          =["+  getMyName1()          +"]");

            Class03A o=new Class03A();
            System.err.println("     o.getMyName2()          =["+o.getMyName2()          +"]");
            System.err.println("     o.myClassName           =["+o.myClassName           +"]");
        }

    }

for completeness the Interface classes:

"mod_A":

     package mtest1;

    public interface I01A
    {
        static public String  getMyClassNameStatic()    // static method in interface
        {
            System.err.println("\t<<<(static public getMyClassNameStatic() method from
    ["+mtest1.I01A.class+"])>>>");
            return "interface-mtest1.I01A"; // myClassName;
        }

        default public String getMyClassName()          // default method in interface
        {
            System.err.println("\t<<<(default public getMyClassName() method from
    ["+mtest1.I01A.class+"])>>>");
            return "interface-mtest1.I01A"; // myClassName;
        }
    }

"mod_B":

    package mtest2;

    public interface I02A extends mtest1.I01A
    {
        static public String  getMyClassNameStatic()    // static method in interface
        {
            System.err.println("\t<<<(static public getMyClassNameStatic() method from
    ["+mtest2.I02A.class+"])>>>");
            return "interface-mtest2.I02A"; // myClassName;
        }

        default public String getMyClassName()          // default method in interface
        {
            System.err.println("\t<<<(default public getMyClassName() method from
    ["+mtest2.I02A.class+"])>>>");
            return "interface-mtest2.I02A"; // myClassName;
        }
    }







More information about the jigsaw-dev mailing list