6378384: (reflect) subclass can’t access superclass’s protected fields and methods by reflection
authorplevart
Tue, 18 Oct 2016 20:28:58 +0200
changeset 41560 a66e7ee16cf9
parent 41559 5b33f33df1fb
child 41561 0c6942d13f2e
6378384: (reflect) subclass can’t access superclass’s protected fields and methods by reflection Reviewed-by: mchung
jdk/src/java.base/share/classes/java/lang/Class.java
jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java
jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java
jdk/src/java.base/share/classes/java/lang/reflect/Field.java
jdk/src/java.base/share/classes/java/lang/reflect/Method.java
jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java
jdk/src/java.base/share/classes/sun/reflect/misc/ReflectUtil.java
jdk/test/java/lang/reflect/AccessControl/AccessControlTest.java
jdk/test/java/lang/reflect/AccessControl/a/Package.java
jdk/test/java/lang/reflect/AccessControl/a/PublicSuper.java
jdk/test/java/lang/reflect/AccessControl/b/Package.java
jdk/test/java/lang/reflect/AccessControl/b/PublicSub.java
jdk/test/java/lang/reflect/AccessControl/util/ClassSupplier.java
jdk/test/java/lang/reflect/AccessControl/util/MemberFactory.java
--- a/jdk/src/java.base/share/classes/java/lang/Class.java	Tue Oct 18 22:17:38 2016 +0530
+++ b/jdk/src/java.base/share/classes/java/lang/Class.java	Tue Oct 18 20:28:58 2016 +0200
@@ -557,7 +557,7 @@
         Class<?> caller = Reflection.getCallerClass();
         if (newInstanceCallerCache != caller) {
             int modifiers = tmpConstructor.getModifiers();
-            Reflection.ensureMemberAccess(caller, this, null, modifiers);
+            Reflection.ensureMemberAccess(caller, this, this, modifiers);
             newInstanceCallerCache = caller;
         }
         // Run constructor
--- a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java	Tue Oct 18 22:17:38 2016 +0530
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java	Tue Oct 18 20:28:58 2016 +0200
@@ -312,22 +312,22 @@
     // (See also Class.newInstance(), which uses a similar method.)
     //
     // A more complicated security check cache is needed for Method and Field
-    // The cache can be either null (empty cache), a 2-array of {caller,target},
-    // or a caller (with target implicitly equal to this.clazz).
-    // In the 2-array case, the target is always different from the clazz.
+    // The cache can be either null (empty cache), a 2-array of {caller,targetClass},
+    // or a caller (with targetClass implicitly equal to memberClass).
+    // In the 2-array case, the targetClass is always different from the memberClass.
     volatile Object securityCheckCache;
 
-    void checkAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers)
+    final void checkAccess(Class<?> caller, Class<?> memberClass,
+                           Class<?> targetClass, int modifiers)
         throws IllegalAccessException
     {
-        if (caller == clazz) {  // quick check
+        if (caller == memberClass) {  // quick check
             return;             // ACCESS IS OK
         }
         Object cache = securityCheckCache;  // read volatile
-        Class<?> targetClass = clazz;
-        if (obj != null
+        if (targetClass != null // instance member or constructor
             && Modifier.isProtected(modifiers)
-            && ((targetClass = obj.getClass()) != clazz)) {
+            && targetClass != memberClass) {
             // Must match a 2-list of { caller, targetClass }.
             if (cache instanceof Class[]) {
                 Class<?>[] cache2 = (Class<?>[]) cache;
@@ -339,25 +339,27 @@
                 // subsumes range check for [0].)
             }
         } else if (cache == caller) {
-            // Non-protected case (or obj.class == this.clazz).
+            // Non-protected case (or targetClass == memberClass or static member).
             return;             // ACCESS IS OK
         }
 
         // If no return, fall through to the slow path.
-        slowCheckMemberAccess(caller, clazz, obj, modifiers, targetClass);
+        slowCheckMemberAccess(caller, memberClass, targetClass, modifiers);
     }
 
     // Keep all this slow stuff out of line:
-    void slowCheckMemberAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers,
-                               Class<?> targetClass)
+    void slowCheckMemberAccess(Class<?> caller, Class<?> memberClass,
+                               Class<?> targetClass, int modifiers)
         throws IllegalAccessException
     {
-        Reflection.ensureMemberAccess(caller, clazz, obj, modifiers);
+        Reflection.ensureMemberAccess(caller, memberClass, targetClass, modifiers);
 
         // Success: Update the cache.
-        Object cache = ((targetClass == clazz)
-                        ? caller
-                        : new Class<?>[] { caller, targetClass });
+        Object cache = (targetClass != null
+                        && Modifier.isProtected(modifiers)
+                        && targetClass != memberClass)
+                        ? new Class<?>[] { caller, targetClass }
+                        : caller;
 
         // Note:  The two cache elements are not volatile,
         // but they are effectively final.  The Java memory model
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java	Tue Oct 18 22:17:38 2016 +0530
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java	Tue Oct 18 20:28:58 2016 +0200
@@ -443,7 +443,7 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, null, modifiers);
+            checkAccess(caller, clazz, clazz, modifiers);
         }
         if ((clazz.getModifiers() & Modifier.ENUM) != 0)
             throw new IllegalArgumentException("Cannot reflectively create enum objects");
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Field.java	Tue Oct 18 22:17:38 2016 +0530
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Field.java	Tue Oct 18 20:28:58 2016 +0200
@@ -403,7 +403,7 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, obj, modifiers);
+            checkAccess(caller, obj);
         }
         return getFieldAccessor(obj).get(obj);
     }
@@ -437,7 +437,7 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, obj, modifiers);
+            checkAccess(caller, obj);
         }
         return getFieldAccessor(obj).getBoolean(obj);
     }
@@ -471,7 +471,7 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, obj, modifiers);
+            checkAccess(caller, obj);
         }
         return getFieldAccessor(obj).getByte(obj);
     }
@@ -507,7 +507,7 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, obj, modifiers);
+            checkAccess(caller, obj);
         }
         return getFieldAccessor(obj).getChar(obj);
     }
@@ -543,7 +543,7 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, obj, modifiers);
+            checkAccess(caller, obj);
         }
         return getFieldAccessor(obj).getShort(obj);
     }
@@ -579,7 +579,7 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, obj, modifiers);
+            checkAccess(caller, obj);
         }
         return getFieldAccessor(obj).getInt(obj);
     }
@@ -615,7 +615,7 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, obj, modifiers);
+            checkAccess(caller, obj);
         }
         return getFieldAccessor(obj).getLong(obj);
     }
@@ -651,7 +651,7 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, obj, modifiers);
+            checkAccess(caller, obj);
         }
         return getFieldAccessor(obj).getFloat(obj);
     }
@@ -687,7 +687,7 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, obj, modifiers);
+            checkAccess(caller, obj);
         }
         return getFieldAccessor(obj).getDouble(obj);
     }
@@ -765,7 +765,7 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, obj, modifiers);
+            checkAccess(caller, obj);
         }
         getFieldAccessor(obj).set(obj, value);
     }
@@ -801,7 +801,7 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, obj, modifiers);
+            checkAccess(caller, obj);
         }
         getFieldAccessor(obj).setBoolean(obj, z);
     }
@@ -837,7 +837,7 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, obj, modifiers);
+            checkAccess(caller, obj);
         }
         getFieldAccessor(obj).setByte(obj, b);
     }
@@ -873,7 +873,7 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, obj, modifiers);
+            checkAccess(caller, obj);
         }
         getFieldAccessor(obj).setChar(obj, c);
     }
@@ -909,7 +909,7 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, obj, modifiers);
+            checkAccess(caller, obj);
         }
         getFieldAccessor(obj).setShort(obj, s);
     }
@@ -945,7 +945,7 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, obj, modifiers);
+            checkAccess(caller, obj);
         }
         getFieldAccessor(obj).setInt(obj, i);
     }
@@ -981,7 +981,7 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, obj, modifiers);
+            checkAccess(caller, obj);
         }
         getFieldAccessor(obj).setLong(obj, l);
     }
@@ -1017,7 +1017,7 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, obj, modifiers);
+            checkAccess(caller, obj);
         }
         getFieldAccessor(obj).setFloat(obj, f);
     }
@@ -1053,11 +1053,20 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, obj, modifiers);
+            checkAccess(caller, obj);
         }
         getFieldAccessor(obj).setDouble(obj, d);
     }
 
+    // check access to field
+    private void checkAccess(Class<?> caller, Object obj)
+        throws IllegalAccessException
+    {
+        checkAccess(caller, clazz,
+                    Modifier.isStatic(modifiers) ? null : obj.getClass(),
+                    modifiers);
+    }
+
     // security check is done before calling this method
     private FieldAccessor getFieldAccessor(Object obj)
         throws IllegalAccessException
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Method.java	Tue Oct 18 22:17:38 2016 +0530
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Method.java	Tue Oct 18 20:28:58 2016 +0200
@@ -526,7 +526,9 @@
     {
         if (!override) {
             Class<?> caller = Reflection.getCallerClass();
-            checkAccess(caller, clazz, obj, modifiers);
+            checkAccess(caller, clazz,
+                        Modifier.isStatic(modifiers) ? null : obj.getClass(),
+                        modifiers);
         }
         MethodAccessor ma = methodAccessor;             // read volatile
         if (ma == null) {
--- a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java	Tue Oct 18 22:17:38 2016 +0530
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java	Tue Oct 18 20:28:58 2016 +0200
@@ -84,9 +84,22 @@
     public static native int getClassAccessFlags(Class<?> c);
 
 
+    /**
+     * Ensures that access to a member is granted and throws
+     * IllegalAccessException if not.
+     *
+     * @param currentClass the class performing the access
+     * @param memberClass the declaring class of the member being accessed
+     * @param targetClass the class of target object if accessing instance
+     *                    field or method;
+     *                    or the declaring class if accessing constructor;
+     *                    or null if accessing static field or method
+     * @param modifiers the member's access modifiers
+     * @throws IllegalAccessException if access to member is denied
+     */
     public static void ensureMemberAccess(Class<?> currentClass,
                                           Class<?> memberClass,
-                                          Object target,
+                                          Class<?> targetClass,
                                           int modifiers)
         throws IllegalAccessException
     {
@@ -94,18 +107,15 @@
             throw new InternalError();
         }
 
-        if (!verifyMemberAccess(currentClass, memberClass, target, modifiers)) {
-            throwIllegalAccessException(currentClass, memberClass, target, modifiers);
+        if (!verifyMemberAccess(currentClass, memberClass, targetClass, modifiers)) {
+            throwIllegalAccessException(currentClass, memberClass, targetClass, modifiers);
         }
     }
 
-    public static boolean verifyMemberAccess(Class<?> currentClass,
-                                             // Declaring class of field
-                                             // or method
-                                             Class<?> memberClass,
-                                             // May be NULL in case of statics
-                                             Object   target,
-                                             int      modifiers)
+    private 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
@@ -162,18 +172,18 @@
             return false;
         }
 
-        if (Modifier.isProtected(modifiers)) {
-            // Additional test for protected members: JLS 6.6.2
-            Class<?> targetClass = (target == null ? memberClass : target.getClass());
-            if (targetClass != currentClass) {
-                if (!gotIsSameClassPackage) {
-                    isSameClassPackage = isSameClassPackage(currentClass, memberClass);
-                    gotIsSameClassPackage = true;
-                }
-                if (!isSameClassPackage) {
-                    if (!isSubclassOf(targetClass, currentClass)) {
-                        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;
                 }
             }
         }
--- a/jdk/src/java.base/share/classes/sun/reflect/misc/ReflectUtil.java	Tue Oct 18 22:17:38 2016 +0530
+++ b/jdk/src/java.base/share/classes/sun/reflect/misc/ReflectUtil.java	Tue Oct 18 20:28:58 2016 +0200
@@ -44,9 +44,21 @@
         return Class.forName(name);
     }
 
-    /*
-     * Reflection.ensureMemberAccess is overly-restrictive
-     * due to a bug. We awkwardly work around it for now.
+    /**
+     * Ensures that access to a method or field is granted and throws
+     * IllegalAccessException if not. This method is not suitable for checking
+     * access to constructors.
+     *
+     * @param currentClass the class performing the access
+     * @param memberClass the declaring class of the member being accessed
+     * @param target the target object if accessing instance field or method;
+     *               or null if accessing static field or method or if target
+     *               object access rights will be checked later
+     * @param modifiers the member's access modifiers
+     * @throws IllegalAccessException if access to member is denied
+     * @implNote Delegates directly to
+     *           {@link Reflection#ensureMemberAccess(Class, Class, Class, int)}
+     *           which should be used instead.
      */
     public static void ensureMemberAccess(Class<?> currentClass,
                                           Class<?> memberClass,
@@ -54,62 +66,10 @@
                                           int modifiers)
         throws IllegalAccessException
     {
-        if (target == null && Modifier.isProtected(modifiers)) {
-            int mods = modifiers;
-            mods = mods & (~Modifier.PROTECTED);
-            mods = mods | Modifier.PUBLIC;
-
-            /*
-             * See if we fail because of class modifiers
-             */
-            Reflection.ensureMemberAccess(currentClass,
-                                          memberClass,
-                                          target,
-                                          mods);
-            try {
-                /*
-                 * We're still here so class access was ok.
-                 * Now try with default field access.
-                 */
-                mods = mods & (~Modifier.PUBLIC);
-                Reflection.ensureMemberAccess(currentClass,
-                                              memberClass,
-                                              target,
-                                              mods);
-                /*
-                 * We're still here so access is ok without
-                 * checking for protected.
-                 */
-                return;
-            } catch (IllegalAccessException e) {
-                /*
-                 * Access failed but we're 'protected' so
-                 * if the test below succeeds then we're ok.
-                 */
-                if (isSubclassOf(currentClass, memberClass)) {
-                    return;
-                } else {
-                    throw e;
-                }
-            }
-        } else {
-            Reflection.ensureMemberAccess(currentClass,
-                                          memberClass,
-                                          target,
-                                          modifiers);
-        }
-    }
-
-    private static boolean isSubclassOf(Class<?> queryClass,
-                                        Class<?> ofClass)
-    {
-        while (queryClass != null) {
-            if (queryClass == ofClass) {
-                return true;
-            }
-            queryClass = queryClass.getSuperclass();
-        }
-        return false;
+        Reflection.ensureMemberAccess(currentClass,
+                                      memberClass,
+                                      target == null ? null : target.getClass(),
+                                      modifiers);
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/AccessControl/AccessControlTest.java	Tue Oct 18 20:28:58 2016 +0200
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import util.ClassSupplier;
+import util.MemberFactory;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import static java.util.stream.Collectors.groupingBy;
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.mapping;
+import static java.util.stream.Collectors.toCollection;
+import static util.MemberFactory.*;
+import static util.MemberFactory.Group.*;
+import static util.ClassSupplier.*;
+
+/**
+ * @test
+ * @summary An exhaustive test of reflective access controls
+ * @bug 6378384
+ * @build a.PublicSuper a.Package b.PublicSub b.Package
+ *        util.MemberFactory util.ClassSupplier
+ * @run main AccessControlTest
+ */
+public class AccessControlTest {
+
+    public static void main(String[] args) throws Exception {
+        boolean ok = true;
+
+        ok &= new Test()
+            .current(PACKAGE_CLASS_IN_PKG_A)
+            .member (PACKAGE_CLASS_IN_PKG_A).target(PACKAGE_CLASS_IN_PKG_A)
+            .allowed(ALL)
+            .perform();
+
+        ok &= new Test()
+            .current(PACKAGE_CLASS_IN_PKG_A)
+            .member (PUBLIC_SUPERCLASS_IN_PKG_A).target(PUBLIC_SUPERCLASS_IN_PKG_A)
+            .allowed(PACKAGE_MEMBERS, PROTECTED_MEMBERS, PUBLIC_MEMBERS)
+            .denied (PRIVATE_MEMBERS)
+            .perform();
+
+        ok &= new Test()
+            .current(PACKAGE_CLASS_IN_PKG_A)
+            .member (PUBLIC_SUPERCLASS_IN_PKG_A).target(PUBLIC_SUBCLASS_IN_PKG_B)
+            .allowed(PACKAGE_MEMBERS, PROTECTED_MEMBERS, PUBLIC_MEMBERS)
+            .denied (PRIVATE_MEMBERS)
+            .perform();
+
+        ok &= new Test()
+            .current(PACKAGE_CLASS_IN_PKG_A)
+            .member (PACKAGE_CLASS_IN_PKG_B).target(PACKAGE_CLASS_IN_PKG_B)
+            .denied (ALL)
+            .perform();
+
+        ok &= new Test()
+            .current(PACKAGE_CLASS_IN_PKG_A)
+            .member (PUBLIC_SUBCLASS_IN_PKG_B).target(PUBLIC_SUBCLASS_IN_PKG_B)
+            .allowed(PUBLIC_MEMBERS)
+            .denied (PRIVATE_MEMBERS, PACKAGE_MEMBERS, PROTECTED_MEMBERS)
+            .perform();
+
+        ok &= new Test()
+            .current(PUBLIC_SUPERCLASS_IN_PKG_A)
+            .member (PACKAGE_CLASS_IN_PKG_A).target(PACKAGE_CLASS_IN_PKG_A)
+            .allowed(PACKAGE_MEMBERS, PROTECTED_MEMBERS, PUBLIC_MEMBERS)
+            .denied (PRIVATE_MEMBERS)
+            .perform();
+
+        ok &= new Test()
+            .current(PUBLIC_SUPERCLASS_IN_PKG_A)
+            .member (PUBLIC_SUPERCLASS_IN_PKG_A).target(PUBLIC_SUPERCLASS_IN_PKG_A)
+            .allowed(ALL)
+            .perform();
+
+        ok &= new Test()
+            .current(PUBLIC_SUPERCLASS_IN_PKG_A)
+            .member (PUBLIC_SUPERCLASS_IN_PKG_A).target(PUBLIC_SUBCLASS_IN_PKG_B)
+            .allowed(ALL)
+            .perform();
+
+        ok &= new Test()
+            .current(PUBLIC_SUPERCLASS_IN_PKG_A)
+            .member (PACKAGE_CLASS_IN_PKG_B).target(PACKAGE_CLASS_IN_PKG_B)
+            .denied (ALL)
+            .perform();
+
+        ok &= new Test()
+            .current(PUBLIC_SUPERCLASS_IN_PKG_A)
+            .member (PUBLIC_SUBCLASS_IN_PKG_B).target(PUBLIC_SUBCLASS_IN_PKG_B)
+            .allowed(PUBLIC_MEMBERS)
+            .denied (PRIVATE_MEMBERS, PACKAGE_MEMBERS, PROTECTED_MEMBERS)
+            .perform();
+
+        ok &= new Test()
+            .current(PACKAGE_CLASS_IN_PKG_B)
+            .member (PACKAGE_CLASS_IN_PKG_A).target(PACKAGE_CLASS_IN_PKG_A)
+            .denied (ALL)
+            .perform();
+
+        ok &= new Test()
+            .current(PACKAGE_CLASS_IN_PKG_B)
+            .member (PUBLIC_SUPERCLASS_IN_PKG_A).target(PUBLIC_SUPERCLASS_IN_PKG_A)
+            .allowed(PUBLIC_MEMBERS)
+            .denied (PRIVATE_MEMBERS, PACKAGE_MEMBERS, PROTECTED_MEMBERS)
+            .perform();
+
+        ok &= new Test()
+            .current(PACKAGE_CLASS_IN_PKG_B)
+            .member (PUBLIC_SUPERCLASS_IN_PKG_A).target(PUBLIC_SUBCLASS_IN_PKG_B)
+            .allowed(PUBLIC_MEMBERS)
+            .denied (PRIVATE_MEMBERS, PACKAGE_MEMBERS, PROTECTED_MEMBERS)
+            .perform();
+
+        ok &= new Test()
+            .current(PACKAGE_CLASS_IN_PKG_B)
+            .member (PACKAGE_CLASS_IN_PKG_B).target(PACKAGE_CLASS_IN_PKG_B)
+            .allowed(ALL)
+            .perform();
+
+        ok &= new Test()
+            .current(PACKAGE_CLASS_IN_PKG_B)
+            .member (PUBLIC_SUBCLASS_IN_PKG_B).target(PUBLIC_SUBCLASS_IN_PKG_B)
+            .allowed(PACKAGE_MEMBERS, PROTECTED_MEMBERS, PUBLIC_MEMBERS)
+            .denied (PRIVATE_MEMBERS)
+            .perform();
+
+        ok &= new Test()
+            .current(PUBLIC_SUBCLASS_IN_PKG_B)
+            .member (PACKAGE_CLASS_IN_PKG_A).target(PACKAGE_CLASS_IN_PKG_A)
+            .denied (ALL)
+            .perform();
+
+        ok &= new Test()
+            .current(PUBLIC_SUBCLASS_IN_PKG_B)
+            .member (PUBLIC_SUPERCLASS_IN_PKG_A).target(PUBLIC_SUPERCLASS_IN_PKG_A)
+            .allowed(PUBLIC_MEMBERS, PROTECTED_STATIC_F_M)
+            .denied (PRIVATE_MEMBERS, PACKAGE_MEMBERS, PROTECTED_INSTANCE_F_M,
+                     PROTECTED_C)
+            .perform();
+
+        ok &= new Test()
+            .current(PUBLIC_SUBCLASS_IN_PKG_B)
+            .member (PUBLIC_SUPERCLASS_IN_PKG_A).target(PUBLIC_SUBCLASS_IN_PKG_B)
+            .allowed(PUBLIC_MEMBERS, PROTECTED_INSTANCE_F_M, PROTECTED_STATIC_F_M)
+            .denied (PRIVATE_MEMBERS, PACKAGE_MEMBERS, PROTECTED_C)
+            .perform();
+
+        ok &= new Test()
+            .current(PUBLIC_SUBCLASS_IN_PKG_B)
+            .member (PACKAGE_CLASS_IN_PKG_B).target(PACKAGE_CLASS_IN_PKG_B)
+            .allowed(PACKAGE_MEMBERS, PROTECTED_MEMBERS, PUBLIC_MEMBERS)
+            .denied (PRIVATE_MEMBERS)
+            .perform();
+
+        ok &= new Test()
+            .current(PUBLIC_SUBCLASS_IN_PKG_B)
+            .member (PUBLIC_SUBCLASS_IN_PKG_B).target(PUBLIC_SUBCLASS_IN_PKG_B)
+            .allowed(ALL)
+            .perform();
+
+        if (ok) {
+            System.out.println("\nAll cases passed.");
+        } else {
+            throw new RuntimeException("Some cases failed - see log.");
+        }
+    }
+
+    // use this for generating an exhaustive set of test cases on stdout
+    public static class Generate {
+        public static void main(String[] args) {
+            for (ClassSupplier current : ClassSupplier.values()) {
+                for (ClassSupplier member : ClassSupplier.values()) {
+                    for (ClassSupplier target : ClassSupplier.values()) {
+                        if (member.get().isAssignableFrom(target.get())) {
+                            new Test()
+                                .current(current).member(member).target(target)
+                                .allowed(ALL)
+                                .perform(true);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    static class Test {
+
+        ClassSupplier currentClassSupplier, memberClassSupplier, targetClassSupplier;
+        EnumSet<MemberFactory> expectAllowedMembers = EnumSet.noneOf(MemberFactory.class);
+        EnumSet<MemberFactory> expectDeniedMembers = EnumSet.noneOf(MemberFactory.class);
+
+        Test current(ClassSupplier current) {
+            currentClassSupplier = current;
+            return this;
+        }
+
+        Test member(ClassSupplier member) {
+            memberClassSupplier = member;
+            return this;
+        }
+
+        Test target(ClassSupplier target) {
+            targetClassSupplier = target;
+            return this;
+        }
+
+        Test allowed(MemberFactory... allowed) {
+            expectAllowedMembers = MemberFactory.asSet(allowed);
+            return this;
+        }
+
+        Test allowed(MemberFactory.Group... allowedGroups) {
+            expectAllowedMembers = MemberFactory.groupsToMembers(
+                MemberFactory.Group.asSet(allowedGroups));
+            return this;
+        }
+
+        Test denied(MemberFactory... denied) {
+            expectDeniedMembers = MemberFactory.asSet(denied);
+            return this;
+        }
+
+        Test denied(MemberFactory.Group... deniedGroups) {
+            expectDeniedMembers = MemberFactory.groupsToMembers(
+                MemberFactory.Group.asSet(deniedGroups));
+            return this;
+        }
+
+        boolean perform() {
+            return perform(false);
+        }
+
+        boolean perform(boolean generateCases) {
+
+            // some validation 1st
+            EnumSet<MemberFactory> intersection = EnumSet.copyOf(expectAllowedMembers);
+            intersection.retainAll(expectDeniedMembers);
+            if (!intersection.isEmpty()) {
+                throw new IllegalArgumentException(
+                    "Expected allowed and denied MemberFactories have non-empty intersection: " +
+                    intersection);
+            }
+
+            EnumSet<MemberFactory> missing = EnumSet.allOf(MemberFactory.class);
+            missing.removeAll(expectAllowedMembers);
+            missing.removeAll(expectDeniedMembers);
+            if (!missing.isEmpty()) {
+                throw new IllegalArgumentException(
+                    "Union of expected allowed and denied MemberFactories is missing elements: " +
+                    missing);
+            }
+
+            // retrieve method that will perform reflective access
+            Method checkAccessMethod;
+            try {
+                checkAccessMethod = currentClassSupplier.get().getDeclaredMethod(
+                    "checkAccess", AccessibleObject.class, Object.class);
+                // in case of inaccessible currentClass
+                checkAccessMethod.setAccessible(true);
+            } catch (NoSuchMethodException e) {
+                throw new RuntimeException(e);
+            }
+
+            // construct a target object (for instance field/method)
+            Object target;
+            Constructor<?> targetConstructor =
+                (Constructor<?>) PUBLIC_CONSTRUCTOR.apply(targetClassSupplier.get());
+            // in case of inaccessible targetClass
+            targetConstructor.setAccessible(true);
+            try {
+                target = targetConstructor.newInstance(
+                    new Object[targetConstructor.getParameterCount()]);
+            } catch (ReflectiveOperationException e) {
+                throw new RuntimeException(e);
+            }
+
+            Class<?> memberClass = memberClassSupplier.get();
+
+            Map<Boolean, EnumSet<MemberFactory>> actualMembers = Stream.concat(
+
+                expectAllowedMembers.stream().map(member -> new Trial(member, true)),
+                expectDeniedMembers.stream().map(member -> new Trial(member, false))
+
+            ).map(trial -> {
+
+                // obtain AccessibleObject to be used to perform reflective access
+                AccessibleObject accessibleObject = trial.member.apply(memberClass);
+
+                // only need target 'obj' for instance fields and methods
+                Object obj =
+                    (accessibleObject instanceof Field &&
+                     !Modifier.isStatic(((Field) accessibleObject).getModifiers())
+                     ||
+                     accessibleObject instanceof Method &&
+                     !Modifier.isStatic(((Method) accessibleObject).getModifiers())
+                    )
+                    ? target : null;
+
+                // invoke checkAccess method and let it perform the reflective access
+                try {
+                    checkAccessMethod.invoke(null, accessibleObject, obj);
+                    trial.actualAllowed = true;
+                } catch (IllegalAccessException e) {
+                    // should not happen as checkAccessMethod.isAccessible()
+                    throw new RuntimeException(e);
+                } catch (InvocationTargetException e) {
+                    if (e.getTargetException() instanceof IllegalAccessException) {
+                        trial.actualAllowed = false;
+                    } else {
+                        // any other Exception is a fault in test or infrastructure - fail fast
+                        throw new RuntimeException(e.getTargetException());
+                    }
+                }
+
+                if (!generateCases) {
+                    System.out.printf(
+                        "%-26s accessing %26s's %-25s %-43s - expected %s, actual %s: %s\n",
+                        currentClassSupplier, memberClassSupplier, trial.member.name(),
+                        (obj == null ? "" : "with instance of " + targetClassSupplier),
+                        (trial.expectAllowed ? "allowed" : "denied "),
+                        (trial.actualAllowed ? "allowed" : "denied "),
+                        (trial.expectAllowed == trial.actualAllowed ? "OK" : "FAILURE")
+                    );
+                }
+
+                return trial;
+
+            }).collect(
+                groupingBy(
+                    Trial::isActualAllowed,
+                    mapping(
+                        Trial::getMember,
+                        toCollection(() -> EnumSet.noneOf(MemberFactory.class))))
+            );
+
+            EnumSet<MemberFactory> actualAllowedMembers =
+                Optional.ofNullable(actualMembers.get(true))
+                        .orElse(EnumSet.noneOf(MemberFactory.class));
+            EnumSet<MemberFactory> actualDeniedMembers =
+                Optional.ofNullable(actualMembers.get(false))
+                        .orElse(EnumSet.noneOf(MemberFactory.class));
+
+            if (generateCases) {
+                System.out.printf(
+                    "        ok &= new Test()\n" +
+                    "            .current(%s)\n" +
+                    "            .member (%s).target(%s)\n",
+                    currentClassSupplier,
+                    memberClassSupplier, targetClassSupplier
+                );
+
+                if (!actualAllowedMembers.isEmpty()) {
+                    EnumSet<? extends Enum> actualAllowed =
+                        MemberFactory.membersToGroupsOrNull(actualAllowedMembers);
+                    if (actualAllowed == null)
+                        actualAllowed = actualAllowedMembers;
+                    System.out.print(
+                        chunkBy(3, actualAllowed.stream().map(Enum::name))
+                            .map(chunk -> chunk.collect(joining(", ")))
+                            .collect(joining(",\n" +
+                                             "                     ",
+                                             "            .allowed(",
+                                             ")\n"))
+                    );
+                }
+
+                if (!actualDeniedMembers.isEmpty()) {
+                    EnumSet<? extends Enum> actualDenied =
+                        MemberFactory.membersToGroupsOrNull(actualDeniedMembers);
+                    if (actualDenied == null)
+                        actualDenied = actualAllowedMembers;
+                    System.out.print(
+                        chunkBy(3, actualDenied.stream().map(Enum::name))
+                            .map(chunk -> chunk.collect(joining(", ")))
+                            .collect(joining(",\n" +
+                                             "                     ",
+                                             "            .denied (",
+                                             ")\n"))
+                    );
+                }
+
+                System.out.print(
+                    "            .perform();\n"
+                );
+            }
+
+            return expectAllowedMembers.equals(actualAllowedMembers) &&
+                   expectDeniedMembers.equals(actualDeniedMembers);
+        }
+    }
+
+    private static <T> Stream<Stream<T>> chunkBy(int chunkSize, Stream<T> stream) {
+        Iterator<T> elements = stream.iterator();
+        Stream.Builder<Stream<T>> b1 = Stream.builder();
+        while (elements.hasNext()) {
+            Stream.Builder<T> b2 = Stream.builder();
+            for (int i = 0; i < chunkSize && elements.hasNext(); i++) {
+                b2.accept(elements.next());
+            }
+            b1.accept(b2.build());
+        }
+        return b1.build();
+    }
+
+    private static class Trial {
+        final MemberFactory member;
+        final boolean expectAllowed;
+        boolean actualAllowed;
+
+        Trial(MemberFactory member, boolean expectAllowed) {
+            this.member = member;
+            this.expectAllowed = expectAllowed;
+        }
+
+        MemberFactory getMember() {
+            return member;
+        }
+
+        boolean isActualAllowed() {
+            return actualAllowed;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/AccessControl/a/Package.java	Tue Oct 18 20:28:58 2016 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package a;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * A package-private class in a.
+ */
+class Package {
+
+    // fields
+    private static int privateStatic;
+    private int privateInstance;
+    static int packageStatic;
+    int packageInstance;
+    protected static int protectedStatic;
+    protected int protectedInstance;
+    public static int publicStatic;
+    public int publicInstance;
+
+    // methods
+    private static int privateStatic() { return 42; }
+    private int privateInstance() { return 42; }
+    static int packageStatic() { return 42; }
+    int packageInstance() { return 42; }
+    protected static int protectedStatic() { return 42; }
+    protected int protectedInstance() { return 42; }
+    public static int publicStatic() { return 42; }
+    public int publicInstance() { return 42; }
+
+    // constructors
+    private Package(Void _1, Void _2, Void _3) {}
+    Package(Void _1, Void _2) {}
+    protected Package(Void _1) {}
+    public Package() {}
+
+
+    // testing method
+    public static void checkAccess(AccessibleObject accessibleObject, Object obj)
+        throws IllegalAccessException,
+               InvocationTargetException,
+               InstantiationException
+    {
+        if (accessibleObject instanceof Field) {
+            Field field = (Field) accessibleObject;
+            field.set(obj, 42);
+            field.get(obj);
+        } else if (accessibleObject instanceof Method) {
+            Method method = (Method) accessibleObject;
+            method.invoke(obj);
+        } else if (accessibleObject instanceof Constructor) {
+            Constructor<?> constructor = (Constructor<?>) accessibleObject;
+            Object[] params = new Object[constructor.getParameterCount()];
+            constructor.newInstance(params);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/AccessControl/a/PublicSuper.java	Tue Oct 18 20:28:58 2016 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package a;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * A public class in a which is a superclass of public class in b.
+ */
+public class PublicSuper {
+
+    // fields
+    private static int privateStatic;
+    private int privateInstance;
+    static int packageStatic;
+    int packageInstance;
+    protected static int protectedStatic;
+    protected int protectedInstance;
+    public static int publicStatic;
+    public int publicInstance;
+
+    // methods
+    private static int privateStatic() { return 42; }
+    private int privateInstance() { return 42; }
+    static int packageStatic() { return 42; }
+    int packageInstance() { return 42; }
+    protected static int protectedStatic() { return 42; }
+    protected int protectedInstance() { return 42; }
+    public static int publicStatic() { return 42; }
+    public int publicInstance() { return 42; }
+
+    // constructors
+    private PublicSuper(Void _1, Void _2, Void _3) {}
+    PublicSuper(Void _1, Void _2) {}
+    protected PublicSuper(Void _1) {}
+    public PublicSuper() {}
+
+
+    // testing method
+    public static void checkAccess(AccessibleObject accessibleObject, Object obj)
+        throws IllegalAccessException,
+               InvocationTargetException,
+               InstantiationException
+    {
+        if (accessibleObject instanceof Field) {
+            Field field = (Field) accessibleObject;
+            field.set(obj, 42);
+            field.get(obj);
+        } else if (accessibleObject instanceof Method) {
+            Method method = (Method) accessibleObject;
+            method.invoke(obj);
+        } else if (accessibleObject instanceof Constructor) {
+            Constructor<?> constructor = (Constructor<?>) accessibleObject;
+            Object[] params = new Object[constructor.getParameterCount()];
+            constructor.newInstance(params);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/AccessControl/b/Package.java	Tue Oct 18 20:28:58 2016 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package b;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * A package-private class in b.
+ */
+class Package {
+
+    // fields
+    private static int privateStatic;
+    private int privateInstance;
+    static int packageStatic;
+    int packageInstance;
+    protected static int protectedStatic;
+    protected int protectedInstance;
+    public static int publicStatic;
+    public int publicInstance;
+
+    // methods
+    private static int privateStatic() { return 42; }
+    private int privateInstance() { return 42; }
+    static int packageStatic() { return 42; }
+    int packageInstance() { return 42; }
+    protected static int protectedStatic() { return 42; }
+    protected int protectedInstance() { return 42; }
+    public static int publicStatic() { return 42; }
+    public int publicInstance() { return 42; }
+
+    // constructors
+    private Package(Void _1, Void _2, Void _3) {}
+    Package(Void _1, Void _2) {}
+    protected Package(Void _1) {}
+    public Package() {}
+
+
+    // testing method
+    public static void checkAccess(AccessibleObject accessibleObject, Object obj)
+        throws IllegalAccessException,
+               InvocationTargetException,
+               InstantiationException
+    {
+        if (accessibleObject instanceof Field) {
+            Field field = (Field) accessibleObject;
+            field.set(obj, 42);
+            field.get(obj);
+        } else if (accessibleObject instanceof Method) {
+            Method method = (Method) accessibleObject;
+            method.invoke(obj);
+        } else if (accessibleObject instanceof Constructor) {
+            Constructor<?> constructor = (Constructor<?>) accessibleObject;
+            Object[] params = new Object[constructor.getParameterCount()];
+            constructor.newInstance(params);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/AccessControl/b/PublicSub.java	Tue Oct 18 20:28:58 2016 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package b;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * A public class in b which is a subclass of public class in a.
+ */
+public class PublicSub extends a.PublicSuper {
+
+    // fields
+    private static int privateStatic;
+    private int privateInstance;
+    static int packageStatic;
+    int packageInstance;
+    protected static int protectedStatic;
+    protected int protectedInstance;
+    public static int publicStatic;
+    public int publicInstance;
+
+    // methods
+    private static int privateStatic() { return 42; }
+    private int privateInstance() { return 42; }
+    static int packageStatic() { return 42; }
+    int packageInstance() { return 42; }
+    protected static int protectedStatic() { return 42; }
+    protected int protectedInstance() { return 42; }
+    public static int publicStatic() { return 42; }
+    public int publicInstance() { return 42; }
+
+    // constructors
+    private PublicSub(Void _1, Void _2, Void _3) {}
+    PublicSub(Void _1, Void _2) {}
+    protected PublicSub(Void _1) {}
+    public PublicSub() {}
+
+
+    // testing method
+    public static void checkAccess(AccessibleObject accessibleObject, Object obj)
+        throws IllegalAccessException,
+               InvocationTargetException,
+               InstantiationException
+    {
+        if (accessibleObject instanceof Field) {
+            Field field = (Field) accessibleObject;
+            field.set(obj, 42);
+            field.get(obj);
+        } else if (accessibleObject instanceof Method) {
+            Method method = (Method) accessibleObject;
+            method.invoke(obj);
+        } else if (accessibleObject instanceof Constructor) {
+            Constructor<?> constructor = (Constructor<?>) accessibleObject;
+            Object[] params = new Object[constructor.getParameterCount()];
+            constructor.newInstance(params);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/AccessControl/util/ClassSupplier.java	Tue Oct 18 20:28:58 2016 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package util;
+
+import java.util.function.Supplier;
+
+/**
+ * An enumeration of suppliers of test classes.
+ */
+public enum ClassSupplier implements Supplier<Class<?>> {
+    PACKAGE_CLASS_IN_PKG_A("a.Package"),
+    PUBLIC_SUPERCLASS_IN_PKG_A("a.PublicSuper"),
+    PACKAGE_CLASS_IN_PKG_B("b.Package"),
+    PUBLIC_SUBCLASS_IN_PKG_B("b.PublicSub");
+
+    private final String className;
+
+    ClassSupplier(String className) {
+        this.className = className;
+    }
+
+    @Override
+    public Class<?> get() {
+        try {
+            return Class.forName(className);
+        } catch (ClassNotFoundException e) {
+            throw (Error) new NoClassDefFoundError(className).initCause(e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/AccessControl/util/MemberFactory.java	Tue Oct 18 20:28:58 2016 +0200
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package util;
+
+import java.lang.reflect.AccessibleObject;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+import static util.MemberFactory.Kind.CONSTRUCTOR;
+import static util.MemberFactory.Kind.FIELD;
+import static util.MemberFactory.Kind.METHOD;
+
+/**
+ * Enumeration of:
+ * <p>
+ * {private, package, protected, public} x {instance, static} x {field, method}
+ * <p>
+ * and:
+ * <p>
+ * {private, package, protected, public} x {constructor},
+ * <p>
+ * with each element acting as a factory of AccessibleObject(s)
+ * declared by given declaringClass(es).
+ */
+public enum MemberFactory implements Function<Class<?>, AccessibleObject> {
+    // instance fields
+    PRIVATE_INSTANCE_FIELD(FIELD, "privateInstance"),
+    PACKAGE_INSTANCE_FIELD(FIELD, "packageInstance"),
+    PROTECTED_INSTANCE_FIELD(FIELD, "protectedInstance"),
+    PUBLIC_INSTANCE_FIELD(FIELD, "publicInstance"),
+    // instance methods
+    PRIVATE_INSTANCE_METHOD(METHOD, "privateInstance"),
+    PACKAGE_INSTANCE_METHOD(METHOD, "packageInstance"),
+    PROTECTED_INSTANCE_METHOD(METHOD, "protectedInstance"),
+    PUBLIC_INSTANCE_METHOD(METHOD, "publicInstance"),
+    // static fields
+    PRIVATE_STATIC_FIELD(FIELD, "privateStatic"),
+    PACKAGE_STATIC_FIELD(FIELD, "packageStatic"),
+    PROTECTED_STATIC_FIELD(FIELD, "protectedStatic"),
+    PUBLIC_STATIC_FIELD(FIELD, "publicStatic"),
+    // static methods
+    PRIVATE_STATIC_METHOD(METHOD, "privateStatic"),
+    PACKAGE_STATIC_METHOD(METHOD, "packageStatic"),
+    PROTECTED_STATIC_METHOD(METHOD, "protectedStatic"),
+    PUBLIC_STATIC_METHOD(METHOD, "publicStatic"),
+    // constructors
+    PRIVATE_CONSTRUCTOR(CONSTRUCTOR, null, Void.class, Void.class, Void.class),
+    PACKAGE_CONSTRUCTOR(CONSTRUCTOR, null, Void.class, Void.class),
+    PROTECTED_CONSTRUCTOR(CONSTRUCTOR, null, Void.class),
+    PUBLIC_CONSTRUCTOR(CONSTRUCTOR, null),;
+
+    final Kind kind;
+    final String name;
+    final Class<?>[] parameterTypes;
+
+    MemberFactory(Kind kind, String name, Class<?>... parameterTypes) {
+        this.kind = kind;
+        this.name = name;
+        this.parameterTypes = parameterTypes;
+    }
+
+    @Override
+    public AccessibleObject apply(Class<?> declaringClass) {
+        return kind.apply(declaringClass, this);
+    }
+
+    public static EnumSet<MemberFactory> asSet(MemberFactory... members) {
+        return members.length == 0 ? EnumSet.noneOf(MemberFactory.class)
+                                   : EnumSet.copyOf(Arrays.asList(members));
+    }
+
+    /**
+     * @param members the set of MemberFactory(s) to convert to set of
+     *                MemberFactory.Group(s).
+     * @return a set of groups that cover all elements of the members set if
+     * such set of groups exists or null if it doesn't.
+     */
+    public static EnumSet<Group> membersToGroupsOrNull(EnumSet<MemberFactory> members) {
+        EnumSet<MemberFactory> mSet = members.clone();
+        EnumSet<Group> gSet = EnumSet.allOf(Group.class);
+        Iterator<Group> gIter = gSet.iterator();
+        while (gIter.hasNext()) {
+            Group g = gIter.next();
+            if (mSet.containsAll(g.members)) {
+                mSet.removeAll(g.members);
+            } else {
+                gIter.remove();
+            }
+        }
+        return mSet.isEmpty() ? gSet : null;
+    }
+
+    /**
+     * @param groups the set of MemberFactory.Group(s) to convert to set of
+     *               MemberFactory(s).
+     * @return a set of members as a union of members of all groups.
+     */
+    public static EnumSet<MemberFactory> groupsToMembers(EnumSet<Group> groups) {
+        EnumSet<MemberFactory> mSet = EnumSet.noneOf(MemberFactory.class);
+        for (Group g : groups) {
+            mSet.addAll(g.members);
+        }
+        return mSet;
+    }
+
+    enum Kind implements BiFunction<Class<?>, MemberFactory, AccessibleObject> {
+        FIELD {
+            @Override
+            public AccessibleObject apply(Class<?> declaringClass, MemberFactory factory) {
+                assert factory.kind == this;
+                try {
+                    return declaringClass.getDeclaredField(factory.name);
+                } catch (NoSuchFieldException e) {
+                    // a fault in test - fail fast
+                    throw new RuntimeException(e.getMessage());
+                }
+            }
+        },
+        METHOD {
+            @Override
+            public AccessibleObject apply(Class<?> declaringClass, MemberFactory factory) {
+                assert factory.kind == this;
+                try {
+                    return declaringClass.getDeclaredMethod(factory.name, factory.parameterTypes);
+                } catch (NoSuchMethodException e) {
+                    // a fault in test - fail fast
+                    throw new RuntimeException(e.getMessage());
+                }
+            }
+        },
+        CONSTRUCTOR {
+            @Override
+            public AccessibleObject apply(Class<?> declaringClass, MemberFactory factory) {
+                assert factory.kind == this;
+                try {
+                    return declaringClass.getDeclaredConstructor(factory.parameterTypes);
+                } catch (NoSuchMethodException e) {
+                    // a fault in test - fail fast
+                    throw new RuntimeException(e.getMessage());
+                }
+            }
+        }
+    }
+
+    /**
+     * We define groups of MemberFactory(s) for members that commonly
+     * exhibit same access restrictions in various cases in order to allow
+     * specifying groups instead of individual members in the test cases,
+     * making them less verbose.
+     */
+    public enum Group {
+        // all members
+        ALL(MemberFactory.values()),
+        // all private members
+        PRIVATE_MEMBERS(PRIVATE_INSTANCE_FIELD, PRIVATE_INSTANCE_METHOD,
+                        PRIVATE_STATIC_FIELD, PRIVATE_STATIC_METHOD,
+                        PRIVATE_CONSTRUCTOR),
+        // all package members
+        PACKAGE_MEMBERS(PACKAGE_INSTANCE_FIELD, PACKAGE_INSTANCE_METHOD,
+                        PACKAGE_STATIC_FIELD, PACKAGE_STATIC_METHOD,
+                        PACKAGE_CONSTRUCTOR),
+        // all protected members
+        PROTECTED_MEMBERS(PROTECTED_INSTANCE_FIELD, PROTECTED_INSTANCE_METHOD,
+                          PROTECTED_STATIC_FIELD, PROTECTED_STATIC_METHOD,
+                          PROTECTED_CONSTRUCTOR),
+        // all public members
+        PUBLIC_MEMBERS(PUBLIC_INSTANCE_FIELD, PUBLIC_INSTANCE_METHOD,
+                       PUBLIC_STATIC_FIELD, PUBLIC_STATIC_METHOD,
+                       PUBLIC_CONSTRUCTOR),
+        // instance field and method pairs
+        PRIVATE_INSTANCE_F_M(PRIVATE_INSTANCE_FIELD, PRIVATE_INSTANCE_METHOD),
+        PACKAGE_INSTANCE_F_M(PACKAGE_INSTANCE_FIELD, PACKAGE_INSTANCE_METHOD),
+        PROTECTED_INSTANCE_F_M(PROTECTED_INSTANCE_FIELD, PROTECTED_INSTANCE_METHOD),
+        PUBLIC_INSTANCE_F_M(PUBLIC_INSTANCE_FIELD, PUBLIC_INSTANCE_METHOD),
+        // static field and method pairs
+        PRIVATE_STATIC_F_M(PRIVATE_STATIC_FIELD, PRIVATE_STATIC_METHOD),
+        PACKAGE_STATIC_F_M(PACKAGE_STATIC_FIELD, PACKAGE_STATIC_METHOD),
+        PROTECTED_STATIC_F_M(PROTECTED_STATIC_FIELD, PROTECTED_STATIC_METHOD),
+        PUBLIC_STATIC_F_M(PUBLIC_STATIC_FIELD, PUBLIC_STATIC_METHOD),
+        // constructor singles
+        PRIVATE_C(PRIVATE_CONSTRUCTOR),
+        PACKAGE_C(PACKAGE_CONSTRUCTOR),
+        PROTECTED_C(PROTECTED_CONSTRUCTOR),
+        PUBLIC_C(PUBLIC_CONSTRUCTOR);
+
+        final EnumSet<MemberFactory> members;
+
+        Group(MemberFactory... members) {
+            this.members = EnumSet.copyOf(Arrays.asList(members));
+        }
+
+        public static EnumSet<Group> asSet(Group... groups) {
+            return groups.length == 0 ? EnumSet.noneOf(Group.class)
+                                      : EnumSet.copyOf(Arrays.asList(groups));
+        }
+    }
+}