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

David Holmes david.holmes at oracle.com
Wed Dec 14 06:17:57 UTC 2016


On 14/12/2016 8:17 AM, Peter Levart wrote:
> 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.

I'm confused as to what is being argued for/against here. 
setAccessible(true) simply says to disable access checks when the member 
is used. At the time of use you have all the necessary information 
available:
- current class
- member defining class
- receiver class (target class??)

> 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)
>     {

Where does this method exist?

Thanks,
David
-----


>         // 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