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

classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

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

Rony G. Flatscher
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
            {
            }

    --------------------------------------------------------------------------


Reply | Threaded
Open this post in threaded view
|

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

Rony G. Flatscher
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
>             {
>             }
>
>     --------------------------------------------------------------------------
>
>

Reply | Threaded
Open this post in threaded view
|

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

Rony G. Flatscher
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
>>             {
>>             }
>>
>>     --------------------------------------------------------------------------

Reply | Threaded
Open this post in threaded view
|

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

Rony G. Flatscher
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
>>>             {
>>>             }
>>>
>>>     --------------------------------------------------------------------------

Reply | Threaded
Open this post in threaded view
|

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

Alan Bateman
In reply to this post by Rony G. Flatscher
On 23/01/2018 14: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]
>
I don't think the questions and observations in this thread are strictly
modules related. One suggestion is to start with a simpler scenario like
this:

package p;
class C1 {
     public static final int K = 99;
     public static int k() { return K; }
     public final int F = -1;
     public int m() { return F; }
}

package p;
public class C2 extends C1 { }

No modules or qualified exports in the picture for now. The important
part is that C1 is not public but it has public members. You can try
tests to see if references to C2.K, C2.k(), new C2().F, and new C2().m()
will compile and run. You can try the equivalent with core reflection to
see how it differs to static references (you may have to change method m
to be final to prevent javac generating a bridge method in C2).

-Alan.
Reply | Threaded
Open this post in threaded view
|

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

Rony G. Flatscher
Changed the subject to hint at the "p" package example.



On 24.01.2018 15:28, Alan Bateman wrote:
> On 23/01/2018 14:52, Rony G. Flatscher wrote:

... cut ...

 

> I don't think the questions and observations in this thread are strictly modules related. One
> suggestion is to start with a simpler scenario like this:
>
> package p;
> class C1 {
>     public static final int K = 99;
>     public static int k() { return K; }
>     public final int F = -1;
>     public int m() { return F; }
> }
>
> package p;
> public class C2 extends C1 { }
>
> No modules or qualified exports in the picture for now. The important part is that C1 is not
> public but it has public members. You can try tests to see if references to C2.K, C2.k(), new
> C2().F, and new C2().m() will compile and run. You can try the equivalent with core reflection to
> see how it differs to static references (you may have to change method m to be final to prevent
> javac generating a bridge method in C2).
OK, now add to this the following class that uses p.C2 objects to access e.g. m() via it:

    G:\xfer\java9modules\03-20180124-AlanBatmanP\p>type UseC2.java

    public class UseC2
    {
        public static void main (String args[]) {
            p.C2 o=new p.C2();
            System.out.println("o="+o);
            System.out.println("o.m()="+o.m());
        }
    }

Compiling all three classes works.

Running "UseC2" works and outputs:

    G:\xfer\java9modules\03-20180124-AlanBatmanP\p>java -cp ".;.." UseC2
    o=p.C2@66048bfd
    o.m()=-1

So it is possible to access m() via the p.C2 object from UseC2.

---

The modules seem to come into play when reflection or unreflect try to determine whether
accessibility should be granted or not. The current implementations (mistakingly, I think) assume
that access is only to be grantable if the package of the object to reflect is exported to the
reflector.

Rather, it should check whether the reflected member is in a class with a package that gets exported
to the reflector *or* is a superclass of a class which package got exported to the reflector. Or
with other words, once a class is determined that gets exported to the reflector all public members
in all superclasses should be accessible in order to avoid "crippled Java objects CJO" ;) .

java.lang.reflect.* could do that check. In the case of unreflection probably one should be able to
supply an exported class to check accessibility and then only accept object that are instances of at
least that class.

---rony










Reply | Threaded
Open this post in threaded view
|

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

Rony G. Flatscher
Had to leave, hence continuing here.

The purpose of demonstrating that compilable and runnable Java program is simply to proof, that it
is legal to access public members of package private classes, if the access occurs via an instance
of a public subclass.

The reflective version that behaves like the presented compiled version, may be coded like:

    import java.lang.reflect.*;

    public class UseC2Reflective
    {
        public static void main (String args[]) {
            p.C2 o=new p.C2();
            System.out.println("o="+o);

            Class sc=o.getClass().getSuperclass();

            Method rm    =null;
            Object result=null;
            try {
                rm=sc.getDeclaredMethod("m",new Class[0]);

                try {
                    result=rm.invoke(o,new Object[0]);
                }
                catch (Exception e1)
                {
                    rm.setAccessible(true);
                    result=rm.invoke(o,new Object[0]);
                }
            }
            catch (Exception e)
            {
                System.err.println("getDefinedMethod(...) caused exception: "+e);
                e.printStackTrace();
                System.exit(-1);
            }

            System.out.println("o.m()="+o.m());
        }
    }

Running it with Java 9 gives:

    G:\xfer\java9modules\03-20180124-AlanBatmanP\p>java -cp ".;.." UseC2Reflective
    o=p.C2@3cd1f1c8
    o.m()=-1

So this behaves like in the past: it is possible to mimickry a compiled Java program using
reflection with setAccessible.

-----------------

Now turning to the use of setAccessible() and looking up the Javadocs for Java 6, 7, 8 and 9, is
interesting:

  * Javadocs 6:

    public class AccessibleObject
    extends Object
    implements AnnotatedElement

    The AccessibleObject class is the base class for Field, Method and Constructor objects. It
    provides the ability to flag a reflected object as suppressing default Java language access
    control checks when it is used. The access checks--for public, default (package) access,
    protected, and private members--are performed when Fields, Methods or Constructors are used to
    set or get fields, to invoke methods, or to create and initialize new instances of classes,
    respectively.

    Setting the accessible flag in a reflected object permits sophisticated applications with
    sufficient privilege, such as Java Object Serialization or other persistence mechanisms, to
    manipulate objects in a manner that would normally be prohibited.

    Since:
        1.2
    See Also:
        Field, Method, Constructor, ReflectPermission

  * Javadocs 7; this adds a paragraph to the documentation:

    public class AccessibleObject
    extends Object
    implements AnnotatedElement

    The AccessibleObject class is the base class for Field, Method and Constructor objects. It
    provides the ability to flag a reflected object as suppressing default Java language access
    control checks when it is used. The access checks--for public, default (package) access,
    protected, and private members--are performed when Fields, Methods or Constructors are used to
    set or get fields, to invoke methods, or to create and initialize new instances of classes,
    respectively.

    Setting the accessible flag in a reflected object permits sophisticated applications with
    sufficient privilege, such as Java Object Serialization or other persistence mechanisms, to
    manipulate objects in a manner that would normally be prohibited.

    *By default, a reflected object is not accessible.*

  * Javadocs 8; this is the same as for the Javadocs 7.

So the rule is, that a reflected object is not accessible by default, such that one needs to use the
setAccessible() method.

  * Javadocs 9; this rewrites the documentation to read:

    public class AccessibleObject
    extends Object
    implements AnnotatedElement

    The AccessibleObject class is the base class for Field, Method, and Constructor objects (known
    as reflected objects). It provides the ability to flag a reflected object as suppressing checks
    for Java language access control when it is used. This permits sophisticated applications with
    sufficient privilege, such as Java Object Serialization or other persistence mechanisms, to
    manipulate objects in a manner that would normally be prohibited.

    Java language access control prevents use of private members outside their class; package access
    members outside their package; protected members outside their package or subclasses; and public
    members outside their module unless they are declared in an exported package and the user reads
    their module. By default, Java language access control is enforced (with one variation) when
    Fields, Methods, or Constructors are used to get or set fields, to invoke methods, or to create
    and initialize new instances of classes, respectively. Every reflected object checks that the
    code using it is in an appropriate class, package, or module.

    The one variation from Java language access control is that the checks by reflected objects
    assume readability. That is, the module containing the use of a reflected object is assumed to
    read the module in which the underlying field, method, or constructor is declared.

    Whether the checks for Java language access control can be suppressed (and thus, whether access
    can be enabled) depends on whether the reflected object corresponds to a member in an exported
    or open package (see setAccessible(boolean)).

    Since:
        1.2

All of a sudden it states that "access control prevents use of (...) package access members outside
their package (...)" by the "Java language access control", however the compiled Java program is
allowed to do so! I think it makes perfect sense that if a public subclass having package access and
returning an object that the receiver of that object is rightfully entitled to use its public
members available in its class and all of its superclasses. There is no risk that the one who has a
reference to such an object can do any harm, if using public members. (As package classes have
always access to their peer package classes and access to their peer's package members it would
probably not make sense to allow "public" in that context, if access to those members was not
allowed to become "public" outside of the package eventually.)

For the module system it states "(...) prevents (...) public members outside their module unless
they are declared in an exported package and the user reads their module". I think this is not
specified enough. Using the same arguments as in the above paragraph: once an object is handed out,
and if its class or one of its superclasses got exported, then starting with the exported class all
public members of that class and all of its superclasses should be accessible via reflection as
well. There is no risk that the one who has a reference to such an object can do any harm to the
module system, if being restricted of using public members starting with the first exported class
and then all of its superclasses as well.

---rony



On 24.01.2018 16:42, Rony G. Flatscher wrote:

> Changed the subject to hint at the "p" package example.
>
>
>
> On 24.01.2018 15:28, Alan Bateman wrote:
>> On 23/01/2018 14:52, Rony G. Flatscher wrote:
> ... cut ...
>
>  
>> I don't think the questions and observations in this thread are strictly modules related. One
>> suggestion is to start with a simpler scenario like this:
>>
>> package p;
>> class C1 {
>>     public static final int K = 99;
>>     public static int k() { return K; }
>>     public final int F = -1;
>>     public int m() { return F; }
>> }
>>
>> package p;
>> public class C2 extends C1 { }
>>
>> No modules or qualified exports in the picture for now. The important part is that C1 is not
>> public but it has public members. You can try tests to see if references to C2.K, C2.k(), new
>> C2().F, and new C2().m() will compile and run. You can try the equivalent with core reflection to
>> see how it differs to static references (you may have to change method m to be final to prevent
>> javac generating a bridge method in C2).
> OK, now add to this the following class that uses p.C2 objects to access e.g. m() via it:
>
>     G:\xfer\java9modules\03-20180124-AlanBatmanP\p>type UseC2.java
>
>     public class UseC2
>     {
>         public static void main (String args[]) {
>             p.C2 o=new p.C2();
>             System.out.println("o="+o);
>             System.out.println("o.m()="+o.m());
>         }
>     }
>
> Compiling all three classes works.
>
> Running "UseC2" works and outputs:
>
>     G:\xfer\java9modules\03-20180124-AlanBatmanP\p>java -cp ".;.." UseC2
>     o=p.C2@66048bfd
>     o.m()=-1
>
> So it is possible to access m() via the p.C2 object from UseC2.
>
> ---
>
> The modules seem to come into play when reflection or unreflect try to determine whether
> accessibility should be granted or not. The current implementations (mistakingly, I think) assume
> that access is only to be grantable if the package of the object to reflect is exported to the
> reflector.
>
> Rather, it should check whether the reflected member is in a class with a package that gets exported
> to the reflector *or* is a superclass of a class which package got exported to the reflector. Or
> with other words, once a class is determined that gets exported to the reflector all public members
> in all superclasses should be accessible in order to avoid "crippled Java objects CJO" ;) .
>
> java.lang.reflect.* could do that check. In the case of unreflection probably one should be able to
> supply an exported class to check accessibility and then only accept object that are instances of at
> least that class.
>
> ---rony
>
>
>
>

Reply | Threaded
Open this post in threaded view
|

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

Rony G. Flatscher


On 24.01.2018 19:11, Rony G. Flatscher wrote:

... cut ...

> So the rule is, that a reflected object is not accessible by default, such that one needs to use the
> setAccessible() method.
>
>   * Javadocs 9; this rewrites the documentation to read:
>
>     public class AccessibleObject
>     extends Object
>     implements AnnotatedElement
>
>     The AccessibleObject class is the base class for Field, Method, and Constructor objects (known
>     as reflected objects). It provides the ability to flag a reflected object as suppressing checks
>     for Java language access control when it is used. This permits sophisticated applications with
>     sufficient privilege, such as Java Object Serialization or other persistence mechanisms, to
>     manipulate objects in a manner that would normally be prohibited.
>
>     Java language access control prevents use of private members outside their class; package access
>     members outside their package; protected members outside their package or subclasses; and public
>     members outside their module unless they are declared in an exported package and the user reads
>     their module. By default, Java language access control is enforced (with one variation) when
>     Fields, Methods, or Constructors are used to get or set fields, to invoke methods, or to create
>     and initialize new instances of classes, respectively. Every reflected object checks that the
>     code using it is in an appropriate class, package, or module.
>
>     The one variation from Java language access control is that the checks by reflected objects
>     assume readability. That is, the module containing the use of a reflected object is assumed to
>     read the module in which the underlying field, method, or constructor is declared.
>
>     Whether the checks for Java language access control can be suppressed (and thus, whether access
>     can be enabled) depends on whether the reflected object corresponds to a member in an exported
>     or open package (see setAccessible(boolean)).
>
>     Since:
>         1.2
>
> All of a sudden it states that "access control prevents use of (...) package access members outside
> their package (...)" by the "Java language access control", however the compiled Java program is
> allowed to do so!
Sorry, misread that part in my rush (short break between two short meetings): it is of course o.k.
to not allow access to package access members outside their package or subclasses!

There is no general rule here that would prevent access to public access members, except for the new
Module system.

> I think it makes perfect sense that if a public subclass having package access and
> returning an object that the receiver of that object is rightfully entitled to use its public
> members available in its class and all of its superclasses. There is no risk that the one who has a
> reference to such an object can do any harm, if using public members. (As package classes have
> always access to their peer package classes and access to their peer's package members it would
> probably not make sense to allow "public" in that context, if access to those members was not
> allowed to become "public" outside of the package eventually.)
>
> For the module system it states "(...) prevents (...) public members outside their module unless
> they are declared in an exported package and the user reads their module". I think this is not
> specified enough. Using the same arguments as in the above paragraph: once an object is handed out,
> and if its class or one of its superclasses got exported, then starting with the exported class all
> public members of that class and all of its superclasses should be accessible via reflection as
> well. There is no risk that the one who has a reference to such an object can do any harm to the
> module system, if being restricted of using public members starting with the first exported class
> and then all of its superclasses as well.
>
> ---rony
>
... cut ...

---rony

Reply | Threaded
Open this post in threaded view
|

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

Alan Bateman
In reply to this post by Rony G. Flatscher
On 24/01/2018 15:42, Rony G. Flatscher wrote:

>
> OK, now add to this the following class that uses p.C2 objects to
> access e.g. m() via it:
>
>     G:\xfer\java9modules\03-20180124-AlanBatmanP\p>type UseC2.java
>
>     public class UseC2
>     {
>         public static void main (String args[]) {
>             p.C2 o=new p.C2();
>             System.out.println("o="+o);
>             System.out.println("o.m()="+o.m());
>         }
>     }
>
> Compiling all three classes works.
>
> Running "UseC2" works and outputs:
>
>     G:\xfer\java9modules\03-20180124-AlanBatmanP\p>java -cp ".;.." UseC2
>     o=p.C2@66048bfd
>     o.m()=-1
>
> So it is possible to access m() via the p.C2 object from UseC2.
That's right and this is the reason for moving to the simpler example.

To be absolutely sure then you should decompile C2.class to make sure
that there isn't a bridge method calling C1's m2(). If you change m() to
be final then that will keep the bridge method from complicating the
picture.

If you change UseC2 to use core reflection and you hit the issue because
the Method object you get is p.C1.m(). Attempting to invoke this will
fail with IllegalAccessException. In your other mail you show a code
fragment where it catches exceptions and calls setAccessible - I'll
guess that this may have been masking the issue in the Rexx bridge.

For completeness then you may want to try out the new reflection API. I
realize you have to compile to JDK 6 but I think you'll find it will
work the same way as the invokevirtual that o.m() compiles to.

     MethodHandles.Lookup lookup = MethodHandles.lookup();
     MethodType mt = MethodType.methodType(int.class);
     MethodHandle mh = lookup.findVirtual(p.C2.class, "m", mt);
     Object res = mh.invoke(o);

-Alan





Reply | Threaded
Open this post in threaded view
|

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

Rony G. Flatscher

On 24.01.2018 20:48, Alan Bateman wrote:

> On 24/01/2018 15:42, Rony G. Flatscher wrote:
>>
>> OK, now add to this the following class that uses p.C2 objects to access e.g. m() via it:
>>
>>     G:\xfer\java9modules\03-20180124-AlanBatmanP\p>type UseC2.java
>>
>>     public class UseC2
>>     {
>>         public static void main (String args[]) {
>>             p.C2 o=new p.C2();
>>             System.out.println("o="+o);
>>             System.out.println("o.m()="+o.m());
>>         }
>>     }
>>
>> Compiling all three classes works.
>>
>> Running "UseC2" works and outputs:
>>
>>     G:\xfer\java9modules\03-20180124-AlanBatmanP\p>java -cp ".;.." UseC2
>>     o=p.C2@66048bfd
>>     o.m()=-1
>>
>> So it is possible to access m() via the p.C2 object from UseC2.
> That's right and this is the reason for moving to the simpler example.

---
>
> To be absolutely sure then you should decompile C2.class to make sure that there isn't a bridge
> method calling C1's m2(). If you change m() to be final then that will keep the bridge method from
> complicating the picture.
>
> If you change UseC2 to use core reflection and you hit the issue because the Method object you get
> is p.C1.m(). Attempting to invoke this will fail with IllegalAccessException. In your other mail
> you show a code fragment where it catches exceptions and calls setAccessible - I'll guess that
> this may have been masking the issue in the Rexx bridge.
The logic to find a matching Method object is to start out in the object's class for which
reflective invocation is needed. Then using getDeclaredMethods() and look for the public method
(with the sought name and parameters types that can be used for the supplied arguments), if not
found, going up its superclass and repeating the process until a matching Method object is found.
Being sure that the found public Method object is the appropriate one setAccess() makes it accessible.

> For completeness then you may want to try out the new reflection API. I realize you have to
> compile to JDK 6 but I think you'll find it will work the same way as the invokevirtual that o.m()
> compiles to.
It will not be a problem to supply different reflection versions after the rewrite.

>     MethodHandles.Lookup lookup = MethodHandles.lookup();
>     MethodType mt = MethodType.methodType(int.class);
>     MethodHandle mh = lookup.findVirtual(p.C2.class, "m", mt);
>     Object res = mh.invoke(o);
Thank you very much for this snippet, it really helped me a lot to explore MethodHandles in the
context of my problem!

After some testing, it looks like it will allow me to solve the problem, although for a price
consisting of learning a totally different way  (which is o.k. for me personally) of achieving what
used to be simple and safe (accessing only public members via reflection), but potentially also
incurring a performance penalty compared to using only reflection. The expected performance penalty
would be due to the fact that reflection cannot be by passed: the Rexx bridge supplies the member's
names usually in uppercase and primitive values as plain strings, such that one must use reflection
to locate candidate members (need to be public and caselessly carrying the Rexx supplied member
name), then check whether the Rexx supplied arguments can be coerced to the parameter types of the
candidate, and if so access it; if not, check the next candidate. Now, further steps will be
necessary in addition: among them create the MethodType, get the MethodHandle, render the arguments
and invoke it.

---

Is there a possibility to have invoke arguments to MethodHandles be relayed, say to some method
RexxValue2JavaValue, such that one can receive the MethodType, the Rexx arguments and return the
matching type-converted values that should then be used for the invoke operation?

---rony


Reply | Threaded
Open this post in threaded view
|

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

Rony G. Flatscher
In reply to this post by Alan Bateman
Just to conclude this posting: first many thanks to Alan!

Alan's little nutshell example about how to use MethodHandles.Lookup and employ MethodHandle s to
invoke helped me a lot to get afloat with rewriting the reflection part for the bindings also using
MH. The new reflection mechanism has been implemented such that on Java 1.6/6 and 1.7/7 it uses core
reflection (on Java 1.7/7 MethodHandle only reflection runs in some errors that cannot be
circumvented, hence using core reflection) reflection with the need to do setAccessible(true) in
quite a few places. The support for Java 1.8/8 and 9 can use both, core reflection (without a need
for setAccessible() at all!) and MethodHandle reflection (with one case found so far, that does not
work on MH, but with core reflection).

The type of reflection that is being carried out is in all my use cases (my bridge intentionally has
been only supporting public classes and public members) not really specific/relevant to jigsaw. Just
wanted to point that out explicitly.

---

The only grief I have at the moment is with the meaning of "public": "public" has become a homonym
in jigsaw, introducing a *lot* of confusion into Java (one time "public" is public, another time
"public" is not public).

This could be probably eased considerably IMHO, if there was a class Modifier introduced named
"module" that would be set for reflective access to classes from non exported modules.

This would have at least the following benefits:

- communicating (and teaching!) about the publicness of a class can immediately be clarified ("is
the class truly public or does it reside in a non-exported module?"),

- also, programmatically it would be simple to learn whether a class object fetched reflectively is
truly public or not by testing against the presence of such a "Module" modifier bit at runtime in
Java 9 or higher.

---rony


On 24.01.2018 20:48, Alan Bateman wrote:

> On 24/01/2018 15:42, Rony G. Flatscher wrote:
>>
>> OK, now add to this the following class that uses p.C2 objects to access e.g. m() via it:
>>
>>     G:\xfer\java9modules\03-20180124-AlanBatmanP\p>type UseC2.java
>>
>>     public class UseC2
>>     {
>>         public static void main (String args[]) {
>>             p.C2 o=new p.C2();
>>             System.out.println("o="+o);
>>             System.out.println("o.m()="+o.m());
>>         }
>>     }
>>
>> Compiling all three classes works.
>>
>> Running "UseC2" works and outputs:
>>
>>     G:\xfer\java9modules\03-20180124-AlanBatmanP\p>java -cp ".;.." UseC2
>>     o=p.C2@66048bfd
>>     o.m()=-1
>>
>> So it is possible to access m() via the p.C2 object from UseC2.
> That's right and this is the reason for moving to the simpler example.
>
> To be absolutely sure then you should decompile C2.class to make sure that there isn't a bridge
> method calling C1's m2(). If you change m() to be final then that will keep the bridge method from
> complicating the picture.
>
> If you change UseC2 to use core reflection and you hit the issue because the Method object you get
> is p.C1.m(). Attempting to invoke this will fail with IllegalAccessException. In your other mail
> you show a code fragment where it catches exceptions and calls setAccessible - I'll guess that
> this may have been masking the issue in the Rexx bridge.
>
> For completeness then you may want to try out the new reflection API. I realize you have to
> compile to JDK 6 but I think you'll find it will work the same way as the invokevirtual that o.m()
> compiles to.
>
>     MethodHandles.Lookup lookup = MethodHandles.lookup();
>     MethodType mt = MethodType.methodType(int.class);
>     MethodHandle mh = lookup.findVirtual(p.C2.class, "m", mt);
>     Object res = mh.invoke(o);
>
> -Alan

Reply | Threaded
Open this post in threaded view
|

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

Remi Forax


----- Mail original -----
> De: "Rony G. Flatscher" <[hidden email]>
> À: "Alan Bateman" <[hidden email]>, "jigsaw-dev" <[hidden email]>
> Envoyé: Mardi 13 Mars 2018 13:16:49
> Objet: Re: p example (Re: Reflection: how can one access public fields (members) in a superclass ?

> Just to conclude this posting: first many thanks to Alan!
>
> Alan's little nutshell example about how to use MethodHandles.Lookup and employ
> MethodHandle s to
> invoke helped me a lot to get afloat with rewriting the reflection part for the
> bindings also using
> MH. The new reflection mechanism has been implemented such that on Java 1.6/6
> and 1.7/7 it uses core
> reflection (on Java 1.7/7 MethodHandle only reflection runs in some errors that
> cannot be
> circumvented, hence using core reflection) reflection with the need to do
> setAccessible(true) in
> quite a few places. The support for Java 1.8/8 and 9 can use both, core
> reflection (without a need
> for setAccessible() at all!) and MethodHandle reflection (with one case found so
> far, that does not
> work on MH, but with core reflection).
>
> The type of reflection that is being carried out is in all my use cases (my
> bridge intentionally has
> been only supporting public classes and public members) not really
> specific/relevant to jigsaw. Just
> wanted to point that out explicitly.
>
> ---
>
> The only grief I have at the moment is with the meaning of "public": "public"
> has become a homonym
> in jigsaw, introducing a *lot* of confusion into Java (one time "public" is
> public, another time
> "public" is not public).
>
> This could be probably eased considerably IMHO, if there was a class Modifier
> introduced named
> "module" that would be set for reflective access to classes from non exported
> modules.

It already exists, but not at class level,
you can open a module, or each package individually, in that case, setAccessible is allowed.

>
> This would have at least the following benefits:
>
> - communicating (and teaching!) about the publicness of a class can immediately
> be clarified ("is
> the class truly public or does it reside in a non-exported module?"),

Teaching is not a big deal because you can teach package and module at the same time and say that it works like onions or russian dolls,
you have module access, class access and member access, by example, a public field is not really public if the class is not public and the package not exported.
If you take a look from the point of view of accessing a member (and not a class), things are regular at module level and class level.  

>
> - also, programmatically it would be simple to learn whether a class object
> fetched reflectively is
> truly public or not by testing against the presence of such a "Module" modifier
> bit at runtime in
> Java 9 or higher.

you can use Lookup.accessClass() [1].

>
> ---rony

Rémi
[1] https://docs.oracle.com/javase/9/docs/api/java/lang/invoke/MethodHandles.Lookup.html#accessClass-java.lang.Class-

>
>
> On 24.01.2018 20:48, Alan Bateman wrote:
>> On 24/01/2018 15:42, Rony G. Flatscher wrote:
>>>
>>> OK, now add to this the following class that uses p.C2 objects to access e.g.
>>> m() via it:
>>>
>>>     G:\xfer\java9modules\03-20180124-AlanBatmanP\p>type UseC2.java
>>>
>>>     public class UseC2
>>>     {
>>>         public static void main (String args[]) {
>>>             p.C2 o=new p.C2();
>>>             System.out.println("o="+o);
>>>             System.out.println("o.m()="+o.m());
>>>         }
>>>     }
>>>
>>> Compiling all three classes works.
>>>
>>> Running "UseC2" works and outputs:
>>>
>>>     G:\xfer\java9modules\03-20180124-AlanBatmanP\p>java -cp ".;.." UseC2
>>>     o=p.C2@66048bfd
>>>     o.m()=-1
>>>
>>> So it is possible to access m() via the p.C2 object from UseC2.
>> That's right and this is the reason for moving to the simpler example.
>>
>> To be absolutely sure then you should decompile C2.class to make sure that there
>> isn't a bridge
>> method calling C1's m2(). If you change m() to be final then that will keep the
>> bridge method from
>> complicating the picture.
>>
>> If you change UseC2 to use core reflection and you hit the issue because the
>> Method object you get
>> is p.C1.m(). Attempting to invoke this will fail with IllegalAccessException. In
>> your other mail
>> you show a code fragment where it catches exceptions and calls setAccessible -
>> I'll guess that
>> this may have been masking the issue in the Rexx bridge.
>>
>> For completeness then you may want to try out the new reflection API. I realize
>> you have to
>> compile to JDK 6 but I think you'll find it will work the same way as the
>> invokevirtual that o.m()
>> compiles to.
>>
>>     MethodHandles.Lookup lookup = MethodHandles.lookup();
>>     MethodType mt = MethodType.methodType(int.class);
>>     MethodHandle mh = lookup.findVirtual(p.C2.class, "m", mt);
>>     Object res = mh.invoke(o);
>>
> > -Alan
Reply | Threaded
Open this post in threaded view
|

ad 'module' modifier idea (Re: p example (Re: Reflection: how can one access public fields (members) in a superclass ?

Rony G. Flatscher
Just changed the subject to indicate better its content.

On 13.03.2018 14:17, Remi Forax wrote:
... cut ...

> ---
>
> The only grief I have at the moment is with the meaning of "public": "public"
> has become a homonym
> in jigsaw, introducing a *lot* of confusion into Java (one time "public" is
> public, another time
> "public" is not public).
>
> This could be probably eased considerably IMHO, if there was a class Modifier
> introduced named
> "module" that would be set for reflective access to classes from non exported
> modules.
> It already exists, but not at class level,
yes, something like (e.g. from
<http://mail.openjdk.java.net/pipermail/jigsaw-dev/2016-September/009357.html>):

    if (Modifier.isPublic(clazz.getModifiers()) && clazz.getModule().isExported(clazz.getPackageName(), caller.getModule()) ...


> you can open a module, or each package individually, in that case, setAccessible is allowed.
yes, however this adds the need to learn the new concept "open" (which is fine for advanced Java
programmers)

>> This would have at least the following benefits:
>>
>> - communicating (and teaching!) about the publicness of a class can immediately
>> be clarified ("is
>> the class truly public or does it reside in a non-exported module?"),
> Teaching is not a big deal because you can teach package and module at the same time and say that it works like onions or russian dolls,
nice metapher!
> you have module access, class access and member access, by example, a public field is not really public if the class is not public and the package not exported.
> If you take a look from the point of view of accessing a member (and not a class), things are regular at module level and class level.  
in my case, if thinking of teaching it is thinking of  "beginner"/"end-user"/"casual" programmer
type of people (business administration students who are interested in learning programming, however
not much time available in the curriculum to teach it)

>
>> - also, programmatically it would be simple to learn whether a class object
>> fetched reflectively is
>> truly public or not by testing against the presence of such a "Module" modifier
>> bit at runtime in
>> Java 9 or higher.
> you can use Lookup.accessClass() [1].
yes, but this a quite advanced concept, it takes quite some time before arriving and being able to
take advantage of it

> [1] https://docs.oracle.com/javase/9/docs/api/java/lang/invoke/MethodHandles.Lookup.html#accessClass-java.lang.Class-
>
---

There are at least two aspects in the context of the "public" homonym:

  * one is the aspect of conceptually understanding it ("why are 'public' classes sometimes not
    'public'?"), and

  * one is to be able to personally test it (maximum learning effect) with minimal Java skills,
    which is why I would prefer the info that a class is from a non-exported module be given with a 
    hypothetical "module" identfier with the class object (if absent, the class is indeed public to
    the world).

    This way, if a student (or any - expert or casual - Java programmer) uses
    "o.getClass().toString()" would see e.g. "module class xyz.SomeClass" and immediately know that
    this class is from a non-exported module. This would simplify this issue considerably IMHO.

---rony