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

Peter Levart peter.levart at gmail.com
Mon Jan 22 09:58:16 UTC 2018


Hi Rony,

On 01/18/2018 04:11 PM, Rony G. Flatscher wrote:
> On 18.01.2018 10:58, Alan Bateman wrote:
>> On 17/01/2018 18:53, Rony G. Flatscher wrote:
>>> :
>>>
>>> Would you have concrete suggestions for this use-case, i.e. a framework that is not part of a
>>> module, but having a need to access public types from exported packages and get reflective access
>>> to objects supertype's protected members?
>> I think it would be better to start with public members as protected is complicated (and hasn't
>> changed with modules once you establish the class declaring the member is accessible).
>>
>> For your example, you've got a reference to a java.awt.Graphics2D object, the actual
>> implementation type is sun.java2d.SunGraphics2D. The user is attempting to invoke one of the
>> public setRenderingHint methods that Graphics2D defines. You said in one of your mails that the
>> bridge "iterates over all its superclasses" which I take to mean that it recursively looks at the
>> superclass and interfaces to find a public class or interface that defines the target
>> setRenderingHint method. In the example, I expect it would skip sun.java2d.SunGraphics2D if it
>> were non public.
>>
>> Can you extend this check to test if the class is in a package exported by its module. For the
>> example, sun.java2d.SunGraphics2D is in the java.desktop module and this module does not export
>> sun.java2d to everyone. Here is a code fragment to test this:
>>
>> Class<?> clazz = graphicsObj.getClass();
>> boolean isExportedToAll = clazz.getModule().isExported(clazz.getPackageName());
>>
>> (I'm deliberately avoiding the 2-arg isExported to keep things simple for this discussion).
>>
>> If you can incorporate this check into the bridge then I suspect you'll find most of the examples
>> will work.
> Yes, I understand (not being able to use methods in an unexported type's instance, hence the need to
> find an accessible member in a superclass, which means to have a need to also access protected
> members in the superclass) and that is actually my current approach. However, I started out with
> reflecting Fields first and see, whether I can reflectively get access.
>
> The rewritten method resolution would follow next, which would allow me to tackle that warning and
> see whether I can get rid of it. However, before going a wrong route I would like to learn what the
> "official" Java 9 solution would be and try to implement that.
>
> ---rony

Yes, I think you are dealing with two problems here which you have been 
using the same solution for in the past.

The 1st thing you have been doing incorrectly for Java 9, as Alan 
explained, is the idiom: o.getClass().getMethod(...) and the 2nd is that 
you are trying to access protected members on behalf of some other class 
which is a subclass of the protected member's declaring class.

The 1st problem has different solutions which are all doable in Java 9, 
since you are dealing within the confines of public types, public 
members and exported packages. One solution is to search for the most 
specific member in the inheritance hierarchy which is also accessible 
(declared in public type in exported package) which is what Alan suggests.

There might also be another elegant solution which requires some 
re-design of your Rexx interpreter.  When you deal with reference values 
in Rexx (the values that refer to objects in Java), you could track not 
only the value itself but also the "static" type of that value. A 
reference value is always obtained either by calling a constructor, 
accessing a field (either static or instance), by calling a method 
(static or instance) or by accessing an element of some array:

- calling constructor: the "static type" is the class upon which the 
constructor has been called
- accessing a field: the "static type" is the type of the field (i.e. 
Field.getDeclaringClass())
- calling a method: the "static type" is the return type of the method 
(i.e. Method.getReturnType())
- accessing an element of some array: the "static type" is the array's 
"static type"'s component type (i.e. Class.getComponentType() invoked on 
array's "static type" Class).

When you take the "static" type as the starting Class when searching for 
a public member with standard Class.getMethod() or Class.getField(), you 
would then get the correct publicly accessible reflected member. With a 
caveat that this only works when there's no generics involved. If 
there's generics, the logic to compute the correct static type is more 
involved and would sometimes require passing the generic type parameters 
(when invoking constructors of generic classes or generic methods) in 
the syntax of your Rexx language. So you may or may not want to do that. 
Perhaps some library for deep resolving could be of help here (Google 
Guava has some support for that). I guess searching for the most 
specific member in the hierarchy that is also accessible is your best 
bet currently if the goal is to be syntactically backwards compatible in 
the Rexx language.

The 2nd problem is not trivial as you want to access a protected member 
on behalf of some other sub-class of the member's declaring class which 
is not cooperating (voluntarily handing you an instance of its Lookup 
object). This currently requires the package containing the member's 
declaring class to be opened at least to you (the Rexx interpreter) and 
using the member.setAccessible(true) trick or 
MethodHandles.privateLookupIn(declaringClass) equivalent for method 
handles. Which is awkward because libraries packed as modules would 
normally not specify that in their module descriptors and system modules 
don't either. So you are left with either --add-opens command line 
switches or deploying a javaagent to the JVM and using it's API point 
java.lang.instrument.Instrumentation#redefineModule to add opens to 
modules that way. Both approaches are not elegant, but that's what is 
currently available, I think.

Regards, Peter


>
>



More information about the jigsaw-dev mailing list