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

Rony G. Flatscher Rony.Flatscher at wu.ac.at
Wed Jan 17 12:18:42 UTC 2018


On 16.01.2018 20:38, John Rose wrote:
> On Jan 16, 2018, at 10:37 AM, Rony G. Flatscher <Rony.Flatscher at wu.ac.at
> <mailto:Rony.Flatscher at wu.ac.at>> wrote:
>>
>> Well that is probably the core of the problem: who needs to be the subclass, the reflector or the
>> object to be reflected upon (whose inheritance tree is being walked up towards the root class, and
>> if public or protected members are found reflectively accessed)?
>
> Quick comment:
>
> With the core reflection API, the reflector's permissions
> are derived from the reflector, not the class being investigated.
>
> This works fine when a class reflects itself but is not so good for frameworks.
>
> The reflection API in java.lang.invoke, though more limited, does
> support rights delegation through the Lookup object.  This means
> that your "patient" class doesn't need to do the reflection work;
> it can merely create a private lookup in itself and hand it to the
> framework, which can do the reflection on behalf of the patient.
>
> You can even mix the old and new mechanisms (a point I don't
> think I've seen on this thread, although I haven't read it all).
> Given a private lookup object in some patient P, a framework
> class F can create a method handle on a core reflection API
> point that is @CallerSensitive (like Class.forName, etc. etc.)
> which allows F to call that API point with the same rights as
> P, not F.
Thank you for the pointer, reading through
<https://docs.oracle.com/javase/9/docs/api/java/lang/invoke/MethodHandles.Lookup.html> it seems that
the access problem cannot be solved with that package either.

The problem at hand is the fact that the framework in question ("BSF4ooRexx", a bridge between
ooRexx implemented in C++ and Java) is *not* part of any class hierarchy in the module(s) nor
related to any specific module.

A simple example ooRexx program using a Java class that gets intertwined with the three test modules
mod_A (exports mtest1), mod_B (requires mod_A, exports mtest2 to mod_C), mod_C (exports mtest3):

    o=.bsf~new("mtest3.Class03A")             -- create Java object, get and assign proxy ooRexx object
    say "o:" o "o~myClassName:" o~myClassName -- get (static) field value in "mtest1.Class01A",
    accessible via inheritance rules

    ::requires BSF.CLS   -- direct interpreter to load the Java bridge

The basic logic is as follows:

  * load the class "mtest3.Class03A", reflectively get a constructor and create a Java object, store
    it in a Java repository return the key to allow looking up the object
  * ooRexx creates an ooRexx proxy object which will forward all unknown messages to the bridge,
    which in turn determines what is sought and uses reflection to carry out the desired operation
  * the second statement shows the ooRexx object name (the key into the Java registry) and uses the
    bridge to have it look up the field named "myClassName" (there is no message by that name on the
    ooRexx side, so the bridge is used to lookup the proxied Java object; a message is indicated by
    the message operator '~', the tilde, where the receiver is placed left of it and the message
    name right of it)

The reflection logic in the bridge is (simplified) as follows:

  * use the object's 'o' class and look up its declared methods or fields, analyze further, if
    member is 'public', otherwise

      o iterate over all of its superclasses looking up in each class all declared methods or
        fields, analyze further, if member is 'public' *or* 'protected' (looking up a superclass
        'protected' is regarded to be 'public' for the subclass) and, if a matching member is found,
        carry out the operation (in this case a Field.get()) and return its value

This way it is assured that the users of the bridge are never able to get at private or package
private members (nor that they are able to invoke a protected member in the object's type itself).

This logic has been working since Java 1.1 (sic!) throughout all Java versions using Java's
reflection infrastructure.

Java 9 currently breaks this.

Is there currently (in the current implementation) any other means to achieve the same, mandatory
needed functionality in Java 9 that I could use?

---

The current implementation seems to do the following: it checks whether a class is from an  exported
package, if not it creates an exception. If the class is exported it then checks whether the
reflected member is public, if not it creates an exception.

What I would have expected is this: everything like the current implementation, but in the second
step, if the member is not public, check whether the object's class for which the reflection takes
place is a subclass of the class that is being checked and if so, allow protected members to be
accessed as well. Hence: in the example presented, the packages 'mtest1' and 'mtest3' are exported,
the class 'mtest3.Class03A' extends 'mtest2.Class02A' which extends 'mtest1.Class01A'. Therefore the
object of type 'mtest3.Class03A' is a subclass of 'mtest1.Class01A', hence as 'mtest1' is exported
all 'mtest1.Class01A' public *and* protected members should be accessible to the object of the
subtype 'mtest3.Class03A' via reflection in Java 9 as well.

---rony




More information about the jigsaw-dev mailing list