6378384: (reflect) subclass can’t access superclass’s protected fields and methods by reflection

Reviewed-by: mchung
This commit is contained in:
Peter Levart 2016-10-18 20:28:58 +02:00
parent 8233dc0e08
commit f160991436
14 changed files with 1153 additions and 118 deletions

View File

@ -557,7 +557,7 @@ public final class Class<T> implements java.io.Serializable,
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

View File

@ -312,22 +312,22 @@ public class AccessibleObject implements AnnotatedElement {
// (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 @@ public class AccessibleObject implements AnnotatedElement {
// 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

View File

@ -443,7 +443,7 @@ public final class Constructor<T> extends Executable {
{
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");

View File

@ -403,7 +403,7 @@ class Field extends AccessibleObject implements Member {
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
checkAccess(caller, obj);
}
return getFieldAccessor(obj).get(obj);
}
@ -437,7 +437,7 @@ class Field extends AccessibleObject implements Member {
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
checkAccess(caller, obj);
}
return getFieldAccessor(obj).getBoolean(obj);
}
@ -471,7 +471,7 @@ class Field extends AccessibleObject implements Member {
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
checkAccess(caller, obj);
}
return getFieldAccessor(obj).getByte(obj);
}
@ -507,7 +507,7 @@ class Field extends AccessibleObject implements Member {
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
checkAccess(caller, obj);
}
return getFieldAccessor(obj).getChar(obj);
}
@ -543,7 +543,7 @@ class Field extends AccessibleObject implements Member {
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
checkAccess(caller, obj);
}
return getFieldAccessor(obj).getShort(obj);
}
@ -579,7 +579,7 @@ class Field extends AccessibleObject implements Member {
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
checkAccess(caller, obj);
}
return getFieldAccessor(obj).getInt(obj);
}
@ -615,7 +615,7 @@ class Field extends AccessibleObject implements Member {
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
checkAccess(caller, obj);
}
return getFieldAccessor(obj).getLong(obj);
}
@ -651,7 +651,7 @@ class Field extends AccessibleObject implements Member {
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
checkAccess(caller, obj);
}
return getFieldAccessor(obj).getFloat(obj);
}
@ -687,7 +687,7 @@ class Field extends AccessibleObject implements Member {
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
checkAccess(caller, obj);
}
return getFieldAccessor(obj).getDouble(obj);
}
@ -765,7 +765,7 @@ class Field extends AccessibleObject implements Member {
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
checkAccess(caller, obj);
}
getFieldAccessor(obj).set(obj, value);
}
@ -801,7 +801,7 @@ class Field extends AccessibleObject implements Member {
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
checkAccess(caller, obj);
}
getFieldAccessor(obj).setBoolean(obj, z);
}
@ -837,7 +837,7 @@ class Field extends AccessibleObject implements Member {
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
checkAccess(caller, obj);
}
getFieldAccessor(obj).setByte(obj, b);
}
@ -873,7 +873,7 @@ class Field extends AccessibleObject implements Member {
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
checkAccess(caller, obj);
}
getFieldAccessor(obj).setChar(obj, c);
}
@ -909,7 +909,7 @@ class Field extends AccessibleObject implements Member {
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
checkAccess(caller, obj);
}
getFieldAccessor(obj).setShort(obj, s);
}
@ -945,7 +945,7 @@ class Field extends AccessibleObject implements Member {
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
checkAccess(caller, obj);
}
getFieldAccessor(obj).setInt(obj, i);
}
@ -981,7 +981,7 @@ class Field extends AccessibleObject implements Member {
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
checkAccess(caller, obj);
}
getFieldAccessor(obj).setLong(obj, l);
}
@ -1017,7 +1017,7 @@ class Field extends AccessibleObject implements Member {
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
checkAccess(caller, obj);
}
getFieldAccessor(obj).setFloat(obj, f);
}
@ -1053,11 +1053,20 @@ class Field extends AccessibleObject implements Member {
{
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

View File

@ -526,7 +526,9 @@ public final class Method extends Executable {
{
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) {

View File

@ -84,9 +84,22 @@ public class Reflection {
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 @@ public class Reflection {
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 @@ public class Reflection {
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;
}
}
}

View File

@ -44,9 +44,21 @@ public final class ReflectUtil {
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 @@ public final class ReflectUtil {
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);
}
/**

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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));
}
}
}