Discussion:
Reflection: how can one access public fields (members) in a superclass ?
Rony G. Flatscher
2018-01-23 14:52:46 UTC
Permalink
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: ***@5afa04c, o.getMyClassName(): via: this=[***@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
        {
        }

--------------------------------------------------------------------------
Rony G. Flatscher
2018-01-23 17:32:58 UTC
Permalink
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
Post by 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,
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());
            }
        }
o.pubStaticFromClass02A     : static-mtest2.Class02A
o.pubFromClass02A           : instance-mtest2.Class02A
getMyClassName()=[class-mtest1.Class01A]
Here is a 1:1 transcription from the above Java program to Rexx which uses Java reflection to
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
tmpField="pubStaticFromClass02A" exception: "java.lang.IllegalAccessException: class
org.rexxla.bsf.engines.rexx.RexxReflectJava9 cannot access class mtest2.Class02A (in module
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
---------------------------------------------------------------------------
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
        {
        }
--------------------------------------------------------------------------
Rony G. Flatscher
2018-01-23 18:17:47 UTC
Permalink
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
Post by Rony G. Flatscher
Assuming that the sources of "mod_A", "mod_B" and m"od_C" are located in "src", the compilation
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
@echo compiling module mod_B
dir      src\mod_B\*java /s /b > mod_B_source_files.txt
type 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
Assuming that "TestUse_mtest3_Class03A.java" is located in the directory that contains the "out"
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
Post by 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,
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());
            }
        }
o.pubStaticFromClass02A     : static-mtest2.Class02A
o.pubFromClass02A           : instance-mtest2.Class02A
getMyClassName()=[class-mtest1.Class01A]
Here is a 1:1 transcription from the above Java program to Rexx which uses Java reflection to
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
tmpField="pubStaticFromClass02A" exception: "java.lang.IllegalAccessException: class
org.rexxla.bsf.engines.rexx.RexxReflectJava9 cannot access class mtest2.Class02A (in module
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
---------------------------------------------------------------------------
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
        {
        }
--------------------------------------------------------------------------
Rony G. Flatscher
2018-01-24 10:29:58 UTC
Permalink
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: ***@5afa04c, o.getMyClassName(): via: this=[***@5afa04c],
getMyClassName()=[class-mtest1.Class01A]

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

Maybe I miss something obvious.

---rony
Post by Rony G. Flatscher
Was asked off-line for a zip-archive for convenience, hence I created a zip archive and put it on
<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
Post by Rony G. Flatscher
Assuming that the sources of "mod_A", "mod_B" and m"od_C" are located in "src", the compilation
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
@echo compiling module mod_B
dir      src\mod_B\*java /s /b > mod_B_source_files.txt
type 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
Assuming that "TestUse_mtest3_Class03A.java" is located in the directory that contains the "out"
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
Post by 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,
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());
            }
        }
o.pubStaticFromClass02A     : static-mtest2.Class02A
o.pubFromClass02A           : instance-mtest2.Class02A
getMyClassName()=[class-mtest1.Class01A]
Here is a 1:1 transcription from the above Java program to Rexx which uses Java reflection to
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
tmpField="pubStaticFromClass02A" exception: "java.lang.IllegalAccessException: class
org.rexxla.bsf.engines.rexx.RexxReflectJava9 cannot access class mtest2.Class02A (in module
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
---------------------------------------------------------------------------
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
        {
        }
--------------------------------------------------------------------------
Alan Bateman
2018-01-24 14:28:14 UTC
Permalink
Post by 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,
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());
            }
        }
o.pubStaticFromClass02A     : static-mtest2.Class02A
o.pubFromClass02A           : instance-mtest2.Class02A
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.
Rony G. Flatscher
2018-01-24 15:42:11 UTC
Permalink
Changed the subject to hint at the "p" package example.
... cut ...

 
I don't think the questions and observations in this thread are strictly modules related. One
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=***@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
Rony G. Flatscher
2018-01-24 18:11:29 UTC
Permalink
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=***@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
Post by Rony G. Flatscher
Changed the subject to hint at the "p" package example.
... cut ...
 
I don't think the questions and observations in this thread are strictly modules related. One
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).
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.
G:\xfer\java9modules\03-20180124-AlanBatmanP\p>java -cp ".;.." UseC2
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
Rony G. Flatscher
2018-01-24 18:35:50 UTC
Permalink
On 24.01.2018 19:11, Rony G. Flatscher wrote:

... cut ...
Post by Rony G. Flatscher
So the rule is, that a reflected object is not accessible by default, such that one needs to use the
setAccessible() method.
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)).
    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.
Post by Rony G. Flatscher
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
Alan Bateman
2018-01-24 19:48:31 UTC
Permalink
Post by Rony G. Flatscher
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.
G:\xfer\java9modules\03-20180124-AlanBatmanP\p>java -cp ".;.." UseC2
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
Rony G. Flatscher
2018-01-27 18:26:25 UTC
Permalink
Post by Alan Bateman
Post by Rony G. Flatscher
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.
G:\xfer\java9modules\03-20180124-AlanBatmanP\p>java -cp ".;.." UseC2
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.
---
Post by Alan Bateman
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.
Post by Alan Bateman
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.
Post by Alan Bateman
    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
Rony G. Flatscher
2018-03-13 12:16:49 UTC
Permalink
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
Post by Alan Bateman
Post by Rony G. Flatscher
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.
G:\xfer\java9modules\03-20180124-AlanBatmanP\p>java -cp ".;.." UseC2
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
Remi Forax
2018-03-13 13:17:15 UTC
Permalink
----- Mail original -----
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.
- 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-
Post by Alan Bateman
Post by Rony G. Flatscher
OK, now add to this the following class that uses p.C2 objects to access e.g.
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.
G:\xfer\java9modules\03-20180124-AlanBatmanP\p>java -cp ".;.." UseC2
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
Rony G. Flatscher
2018-03-14 14:20:40 UTC
Permalink
Just changed the subject to indicate better its content.

On 13.03.2018 14:17, Remi Forax wrote:
... cut ...
Post by Rony G. Flatscher
---
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()) ...
Post by Rony G. Flatscher
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)
Post by Rony G. Flatscher
Post by Rony G. Flatscher
- 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!
Post by Rony G. Flatscher
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)
Post by Rony G. Flatscher
Post by Rony G. Flatscher
- 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
Post by Rony G. Flatscher
[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

Continue reading on narkive:
Search results for 'Reflection: how can one access public fields (members) in a superclass ?' (Questions and Answers)
4
replies
What is basic difference between java n html?
started 2006-10-04 22:39:43 UTC
software
Loading...