/* * 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)); } } }