--- /dev/null 2016-10-03 16:29:56.482600995 +0200 +++ new/test/java/lang/reflect/AccessControl/util/MemberFactory.java 2016-10-18 13:06:45.819954648 +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: + *

+ * {private, package, protected, public} x {instance, static} x {field, method} + *

+ * and: + *

+ * {private, package, protected, public} x {constructor}, + *

+ * with each element acting as a factory of AccessibleObject(s) + * declared by given declaringClass(es). + */ +public enum MemberFactory implements Function, 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 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 membersToGroupsOrNull(EnumSet members) { + EnumSet mSet = members.clone(); + EnumSet gSet = EnumSet.allOf(Group.class); + Iterator 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 groupsToMembers(EnumSet groups) { + EnumSet mSet = EnumSet.noneOf(MemberFactory.class); + for (Group g : groups) { + mSet.addAll(g.members); + } + return mSet; + } + + enum Kind implements BiFunction, 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 members; + + Group(MemberFactory... members) { + this.members = EnumSet.copyOf(Arrays.asList(members)); + } + + public static EnumSet asSet(Group... groups) { + return groups.length == 0 ? EnumSet.noneOf(Group.class) + : EnumSet.copyOf(Arrays.asList(groups)); + } + } +}