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