blob: c960bd871398ba3cd9c56532cfc119e89afa53e1 [file] [log] [blame]
/*
* 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));
}
}
}