1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package member; 24 25 import java.lang.reflect.AccessibleObject; 26 import java.util.Arrays; 27 import java.util.EnumSet; 28 import java.util.Iterator; 29 import java.util.function.BiFunction; 30 import java.util.function.Function; 31 32 import static member.MemberFactory.Kind.CONSTRUCTOR; 33 import static member.MemberFactory.Kind.FIELD; 34 import static member.MemberFactory.Kind.METHOD; 35 36 /** 37 * Enumeration of: 38 * <p> 39 * {private, package, protected, public} x {instance, static} x {field, method} 40 * <p> 41 * and: 42 * <p> 43 * {private, package, protected, public} x {constructor}, 44 * <p> 45 * with each element acting as a factory of AccessibleObject(s) 46 * declared by given declaringClass(es). 47 */ 48 public enum MemberFactory implements Function<Class<?>, AccessibleObject> { 49 // instance fields 50 PRIVATE_INSTANCE_FIELD(FIELD, "privateInstance"), 51 PACKAGE_INSTANCE_FIELD(FIELD, "packageInstance"), 52 PROTECTED_INSTANCE_FIELD(FIELD, "protectedInstance"), 53 PUBLIC_INSTANCE_FIELD(FIELD, "publicInstance"), 54 // instance methods 55 PRIVATE_INSTANCE_METHOD(METHOD, "privateInstance"), 56 PACKAGE_INSTANCE_METHOD(METHOD, "packageInstance"), 57 PROTECTED_INSTANCE_METHOD(METHOD, "protectedInstance"), 58 PUBLIC_INSTANCE_METHOD(METHOD, "publicInstance"), 59 // static fields 60 PRIVATE_STATIC_FIELD(FIELD, "privateStatic"), 61 PACKAGE_STATIC_FIELD(FIELD, "packageStatic"), 62 PROTECTED_STATIC_FIELD(FIELD, "protectedStatic"), 63 PUBLIC_STATIC_FIELD(FIELD, "publicStatic"), 64 // static methods 65 PRIVATE_STATIC_METHOD(METHOD, "privateStatic"), 66 PACKAGE_STATIC_METHOD(METHOD, "packageStatic"), 67 PROTECTED_STATIC_METHOD(METHOD, "protectedStatic"), 68 PUBLIC_STATIC_METHOD(METHOD, "publicStatic"), 69 // constructors 70 PRIVATE_CONSTRUCTOR(CONSTRUCTOR, null, Void.class, Void.class, Void.class), 71 PACKAGE_CONSTRUCTOR(CONSTRUCTOR, null, Void.class, Void.class), 72 PROTECTED_CONSTRUCTOR(CONSTRUCTOR, null, Void.class), 73 PUBLIC_CONSTRUCTOR(CONSTRUCTOR, null),; 74 75 final Kind kind; 76 final String name; 77 final Class<?>[] parameterTypes; 78 79 MemberFactory(Kind kind, String name, Class<?>... parameterTypes) { 80 this.kind = kind; 81 this.name = name; 82 this.parameterTypes = parameterTypes; 83 } 84 85 @Override 86 public AccessibleObject apply(Class<?> declaringClass) { 87 return kind.apply(declaringClass, this); 88 } 89 90 public static EnumSet<MemberFactory> asSet(MemberFactory... members) { 91 return members.length == 0 ? EnumSet.noneOf(MemberFactory.class) 92 : EnumSet.copyOf(Arrays.asList(members)); 93 } 94 95 /** 96 * @param members the set of MemberFactory(s) to convert to set of 97 * MemberFactory.Group(s). 98 * @return a set of groups that cover all elements of the members set if 99 * such set of groups exists or null if it doesn't. 100 */ 101 public static EnumSet<Group> membersToGroupsOrNull(EnumSet<MemberFactory> members) { 102 EnumSet<MemberFactory> mSet = members.clone(); 103 EnumSet<Group> gSet = EnumSet.allOf(Group.class); 104 Iterator<Group> gIter = gSet.iterator(); 105 while (gIter.hasNext()) { 106 Group g = gIter.next(); 107 if (mSet.containsAll(g.members)) { 108 mSet.removeAll(g.members); 109 } else { 110 gIter.remove(); 111 } 112 } 113 return mSet.isEmpty() ? gSet : null; 114 } 115 116 /** 117 * @param groups the set of MemberFactory.Group(s) to convert to set of 118 * MemberFactory(s). 119 * @return a set of members as a union of members of all groups. 120 */ 121 public static EnumSet<MemberFactory> groupsToMembers(EnumSet<Group> groups) { 122 EnumSet<MemberFactory> mSet = EnumSet.noneOf(MemberFactory.class); 123 for (Group g : groups) { 124 mSet.addAll(g.members); 125 } 126 return mSet; 127 } 128 129 enum Kind implements BiFunction<Class<?>, MemberFactory, AccessibleObject> { 130 FIELD { 131 @Override 132 public AccessibleObject apply(Class<?> declaringClass, MemberFactory factory) { 133 assert factory.kind == this; 134 try { 135 return declaringClass.getDeclaredField(factory.name); 136 } catch (NoSuchFieldException e) { 137 // a fault in test - fail fast 138 throw new RuntimeException(e.getMessage()); 139 } 140 } 141 }, 142 METHOD { 143 @Override 144 public AccessibleObject apply(Class<?> declaringClass, MemberFactory factory) { 145 assert factory.kind == this; 146 try { 147 return declaringClass.getDeclaredMethod(factory.name, factory.parameterTypes); 148 } catch (NoSuchMethodException e) { 149 // a fault in test - fail fast 150 throw new RuntimeException(e.getMessage()); 151 } 152 } 153 }, 154 CONSTRUCTOR { 155 @Override 156 public AccessibleObject apply(Class<?> declaringClass, MemberFactory factory) { 157 assert factory.kind == this; 158 try { 159 return declaringClass.getDeclaredConstructor(factory.parameterTypes); 160 } catch (NoSuchMethodException e) { 161 // a fault in test - fail fast 162 throw new RuntimeException(e.getMessage()); 163 } 164 } 165 } 166 } 167 168 /** 169 * We know fields and methods share the same access control rules. 170 * We therefore define groups of MemberFactory(s) for members that should 171 * exhibit same access restrictions in order to allow specifying groups 172 * instead of individual members in the test cases, making them less verbose. 173 */ 174 public enum Group { 175 // instance field and method pairs 176 PRIVATE_INSTANCE_F_M(PRIVATE_INSTANCE_FIELD, PRIVATE_INSTANCE_METHOD), 177 PACKAGE_INSTANCE_F_M(PACKAGE_INSTANCE_FIELD, PACKAGE_INSTANCE_METHOD), 178 PROTECTED_INSTANCE_F_M(PROTECTED_INSTANCE_FIELD, PROTECTED_INSTANCE_METHOD), 179 PUBLIC_INSTANCE_F_M(PUBLIC_INSTANCE_FIELD, PUBLIC_INSTANCE_METHOD), 180 // static field and method pairs 181 PRIVATE_STATIC_F_M(PRIVATE_STATIC_FIELD, PRIVATE_STATIC_METHOD), 182 PACKAGE_STATIC_F_M(PACKAGE_STATIC_FIELD, PACKAGE_STATIC_METHOD), 183 PROTECTED_STATIC_F_M(PROTECTED_STATIC_FIELD, PROTECTED_STATIC_METHOD), 184 PUBLIC_STATIC_F_M(PUBLIC_STATIC_FIELD, PUBLIC_STATIC_METHOD), 185 // constructor singles 186 PRIVATE_C(PRIVATE_CONSTRUCTOR), 187 PACKAGE_C(PACKAGE_CONSTRUCTOR), 188 PROTECTED_C(PROTECTED_CONSTRUCTOR), 189 PUBLIC_C(PUBLIC_CONSTRUCTOR); 190 191 final EnumSet<MemberFactory> members; 192 193 Group(MemberFactory... members) { 194 this.members = EnumSet.copyOf(Arrays.asList(members)); 195 } 196 197 public static EnumSet<Group> asSet(Group... groups) { 198 return groups.length == 0 ? EnumSet.noneOf(Group.class) 199 : EnumSet.copyOf(Arrays.asList(groups)); 200 } 201 } 202 }