Question ad #AwkwardStrongEncapsulation (Re: Moving the changes in jake to jdk9/dev

Peter Levart peter.levart at gmail.com
Tue Dec 13 22:17:55 UTC 2016


Hi Jochen,


On 12/13/2016 06:32 PM, Jochen Theodorou wrote:
>
>
> On 12.12.2016 20:56, Alex Buckley wrote:
> [...]
>> The ability of protected members to be accessed from outside their
>> package means they are essentially public members for the purposes of
>> inheritance and reflection. So, setAccessible should work for protected
>> members of exported packages. I know what you mean about the receiver
>> object being of the correct class, but that's outside the capability of
>> setAccessible to check, so I don't believe it is checked.
>
> why does it have to be checked? why not just allow it? I mean that is 
> why I use setAccessible in the first place. I have much less use of 
> making something accessible for which I already have access rights
>
> bye Jochen

You might have access to a protected method, but you can not delegate 
that access to a 3rd party unless you make the Method object 
.setAccessible(true) and pass it to the 3rd party as a capability. (I 
recommend using MethodHandle(s) for such delegation of rights instead of 
reflection though).

But let me explain why .setAccessible(true) can't be allowed for 
protected members in general.

Jigsaw establishes strong encapsulation. What that means is that even 
without a SecurityManager present, code should not be allowed to gain 
access to a member beyond what is allowed by accessibility rules of Java 
language unless that member is in a class in an open package or such 
access is willingly delegated to code by some other code. For core 
reflection that means the following check is performed each time a 
reflective access is performed:

     /**
      * Verify access to a member, returning {@code false} if no access
      */
     public static boolean verifyMemberAccess(Class<?> currentClass,
                                              Class<?> memberClass,
                                              Class<?> targetClass,
                                              int modifiers)
     {
         // Verify that currentClass can access a field, method, or
         // constructor of memberClass, where that member's access bits are
         // "modifiers".

         boolean gotIsSameClassPackage = false;
         boolean isSameClassPackage = false;

         if (currentClass == memberClass) {
             // Always succeeds
             return true;
         }

         if (!verifyModuleAccess(currentClass, memberClass)) {
             return false;
         }

         if (!Modifier.isPublic(getClassAccessFlags(memberClass))) {
             isSameClassPackage = isSameClassPackage(currentClass, 
memberClass);
             gotIsSameClassPackage = true;
             if (!isSameClassPackage) {
                 return false;
             }
         }

         // At this point we know that currentClass can access memberClass.

         if (Modifier.isPublic(modifiers)) {
             return true;
         }

         boolean successSoFar = false;

         if (Modifier.isProtected(modifiers)) {
             // See if currentClass is a subclass of memberClass
             if (isSubclassOf(currentClass, memberClass)) {
                 successSoFar = true;
             }
         }

         if (!successSoFar && !Modifier.isPrivate(modifiers)) {
             if (!gotIsSameClassPackage) {
                 isSameClassPackage = isSameClassPackage(currentClass,
memberClass);
                 gotIsSameClassPackage = true;
             }

             if (isSameClassPackage) {
                 successSoFar = true;
             }
         }

         if (!successSoFar) {
             return false;
         }

         // Additional test for protected instance members
         // and protected constructors: JLS 6.6.2
         if (targetClass != null && Modifier.isProtected(modifiers) &&
             targetClass != currentClass)
         {
             if (!gotIsSameClassPackage) {
                 isSameClassPackage = isSameClassPackage(currentClass, 
memberClass);
                 gotIsSameClassPackage = true;
             }
             if (!isSameClassPackage) {
                 if (!isSubclassOf(targetClass, currentClass)) {
                     return false;
                 }
             }
         }

         return true;
     }


The interesting part is at the end - the additional test for protected 
instance members. You can't perform the access check for a protected 
instance member without knowing the 'targetClass' (the runtime class of 
the target instance). The protected member must be declared by the same 
class (memberClass) or a superclass of the class from where you are 
accessing it (currentClass), but to allow access to the protected 
instance member, the runtime class of the target instance (targetClass) 
must also be the same as or a subclass of the class from where you are 
accessing the member (currentClass).

You don't know in advance what target instance will be used when 
deciding whether to allow .setAccessible(true) for an instance member.

Regards, Peter



More information about the jigsaw-dev mailing list