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@4973813a] package: [package mtest3] module: 
[module mod_C]
    org.rexxla.bsf.engines.rexx.RexxReflectJava9@6fb0d3ed -> reflect(rru):
    org.rexxla.bsf.engines.rexx.RexxReflectUtil@16f7c8c1, field values:
    --->    rajo          =[org.rexxla.bsf.engines.rexx.RexxAndJava@24a35978]
            invocationType=[GET_FIELD_VALUE]
            reflectionType=[REFLECT_FIELD]
            bStrict       =[false]
            beanName      =[mtest3.Class03A@1563da5]
            bean          =[mtest3.Class03A@1563da5] instanceof Class? [false]
            beanClz       =[class mtest3.Class03A]
            memberName    =[MYCLASSNAME]
            rexxArgs[]    =[[Ljava.lang.String;@df27fae], rexxArgs.length   
=[3]: [GETFIELDVALUE,
    mtest3.Class03A@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@1563da5]
    RexxReflectJava9.processField(): => [GET_FIELD_VALUE]: found 
field=[MYCLASSNAME] in
    object=[mtest3.Class03A@1563da5/mtest3.Class03A@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;
        }
    }





Reply via email to