6378384: (reflect) subclass can’t access superclass’s protected fields and methods by reflection
Reviewed-by: mchung
--- 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));
+ }
+ }
+}