3789983e89
Reviewed-by: darcy, ihse
221 lines
8.8 KiB
Java
221 lines
8.8 KiB
Java
/*
|
|
* 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));
|
|
}
|
|
}
|
|
}
|