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

Reply via email to