1 /* 2 * Copyright (c) 2022, 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 24 /* 25 * @test 26 * @bug 8266670 8291734 8296743 27 * @summary Test expected AccessFlag's on classes. 28 */ 29 30 import java.lang.annotation.*; 31 import java.lang.reflect.*; 32 import java.util.*; 33 34 /* 35 * Class access flags that can directly or indirectly declared in 36 * source include: 37 * public, private, protected, static, final, interface, abstract, 38 * annotation, enum. 39 * 40 * Additionally, the access flags super and synthetic cannot be 41 * explicitly applied. 42 * 43 * This test is written on top of the facilities of core reflection. 44 * 45 * Note that core reflection does not offer a supported mechanism to 46 * return the Class object created from a module-info.class 47 * file. Therefore, this test does not attempt to probe the setting of 48 * that access flag. 49 */ 50 @ExpectedClassFlags("[PUBLIC, FINAL, IDENTITY]") 51 public final class ClassAccessFlagTest { 52 public static void main(String... args) { 53 // Top-level and auxiliary classes; i.e. non-inner classes 54 Class<?>[] testClasses = { 55 ClassAccessFlagTest.class, 56 TestInterface.class, 57 TestIdentityInterface.class, 58 TestValueInterface.class, 59 ExpectedClassFlags.class, 60 TestOuterEnum.class 61 }; 62 checkClasses(testClasses); 63 64 // Nested classes of ClassAccessFlagTest 65 checkClasses(ClassAccessFlagTest.class.getDeclaredClasses()); 66 67 checkPrimitives(); 68 checkArrays(); 69 } 70 71 private static void checkClasses(Class<?>[] classes) { 72 for (var clazz : classes) { 73 checkClass(clazz); 74 } 75 } 76 77 private static void checkClass(Class<?> clazz) { 78 ExpectedClassFlags expected = 79 clazz.getAnnotation(ExpectedClassFlags.class); 80 if (expected != null) { 81 String actual = clazz.accessFlags().toString(); 82 if (!expected.value().equals(actual)) { 83 throw new RuntimeException("On " + clazz + 84 " expected " + expected.value() + 85 " got " + actual); 86 } 87 } 88 } 89 90 private static void checkPrimitives() { 91 final Class<?>[] primitives = { 92 byte.class, 93 int.class, 94 long.class, 95 short.class, 96 char.class, 97 float.class, 98 double.class, 99 boolean.class, 100 void.class // same access flag rules 101 }; 102 103 var expected = Set.of(AccessFlag.PUBLIC, 104 AccessFlag.FINAL, 105 AccessFlag.ABSTRACT); 106 107 for(var primClass : primitives) { 108 var accessFlags = primClass.accessFlags(); 109 if (!accessFlags.equals(expected)) { 110 throw new RuntimeException("Unexpected flags on " + 111 primClass); 112 } 113 } 114 } 115 116 private static boolean containsAny(Set<AccessFlag> input, 117 Set<AccessFlag> test) { 118 var copy = new HashSet<>(input); 119 return copy.removeAll(test); 120 } 121 122 private static void checkArrays() { 123 Class<?>[] accessClasses = { 124 PublicInterface.class, 125 ProtectedInterface.class, 126 PrivateInterface.class, 127 }; 128 129 for (var accessClass : accessClasses) { 130 AccessFlag accessLevel; 131 var flags = accessClass.accessFlags(); 132 if (flags.contains(AccessFlag.PUBLIC)) 133 accessLevel = AccessFlag.PUBLIC; 134 else if (flags.contains(AccessFlag.PROTECTED)) 135 accessLevel = AccessFlag.PROTECTED; 136 else if (flags.contains(AccessFlag.PRIVATE)) 137 accessLevel = AccessFlag.PRIVATE; 138 else 139 accessLevel = null; 140 141 var arrayClass = accessClass.arrayType(); 142 // Access modifier must match on the array type 143 if (accessLevel != null) { 144 if (!arrayClass.accessFlags().contains(accessLevel)) { 145 throw new RuntimeException("Mismatched access flags on " + 146 arrayClass); 147 } 148 } else { 149 if (containsAny(arrayClass.accessFlags(), 150 Set.of(AccessFlag.PUBLIC, 151 AccessFlag.PROTECTED, 152 AccessFlag.PRIVATE))) { 153 throw new RuntimeException("Unexpected access flags on " + 154 arrayClass); 155 } 156 } 157 // Verify IDENTITY, ABSTRACT, FINAL, and access mode 158 Set<AccessFlag> expected = new HashSet<>(4); 159 expected.add(AccessFlag.ABSTRACT); 160 expected.add(AccessFlag.FINAL); 161 // expected.add(AccessFlag.IDENTITY); // NYI Pending: JDK-8294866 162 if (accessLevel != null) 163 expected.add(accessLevel); 164 if (!expected.equals(arrayClass.accessFlags())) { 165 throw new RuntimeException("Unexpected access flags for array: " + accessClass + 166 ": actual: " + arrayClass.accessFlags() + 167 ", expected: " + expected); 168 } 169 } 170 171 } 172 173 // inner classes and interfaces; possible flags on INNER_CLASS 174 // locations: 175 // PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, INTERFACE, ABSTRACT, 176 // SYNTHETIC, ANNOTATION, ENUM. 177 // Include cases for classes with identity, value modifier, or no modifier. 178 179 @ExpectedClassFlags("[PUBLIC, STATIC, INTERFACE, ABSTRACT]") 180 public interface PublicInterface {} 181 @ExpectedClassFlags("[PUBLIC, STATIC, IDENTITY, INTERFACE, ABSTRACT]") 182 public identity interface PublicIdentityInterface {} 183 @ExpectedClassFlags("[PUBLIC, STATIC, VALUE, INTERFACE, ABSTRACT]") 184 public value interface PublicValueInterface {} 185 186 @ExpectedClassFlags("[PROTECTED, STATIC, INTERFACE, ABSTRACT]") 187 protected interface ProtectedInterface {} 188 @ExpectedClassFlags("[PROTECTED, STATIC, IDENTITY, INTERFACE, ABSTRACT]") 189 protected identity interface ProtectedIdentityInterface {} 190 @ExpectedClassFlags("[PROTECTED, STATIC, VALUE, INTERFACE, ABSTRACT]") 191 protected value interface ProtectedValueInterface {} 192 193 @ExpectedClassFlags("[PRIVATE, STATIC, INTERFACE, ABSTRACT]") 194 private interface PrivateInterface {} 195 @ExpectedClassFlags("[PRIVATE, STATIC, IDENTITY, INTERFACE, ABSTRACT]") 196 private identity interface PrivateIdentityInterface {} 197 @ExpectedClassFlags("[PRIVATE, STATIC, VALUE, INTERFACE, ABSTRACT]") 198 private value interface PrivateValueInterface {} 199 200 @ExpectedClassFlags("[STATIC, INTERFACE, ABSTRACT]") 201 /*package*/ interface PackageInterface {} 202 @ExpectedClassFlags("[STATIC, IDENTITY, INTERFACE, ABSTRACT]") 203 /*package*/ identity interface PackageIdentityInterface {} 204 @ExpectedClassFlags("[STATIC, VALUE, INTERFACE, ABSTRACT]") 205 /*package*/ value interface PackageValueInterface {} 206 207 @ExpectedClassFlags("[FINAL, IDENTITY]") 208 /*package*/ final class TestFinalClass {} 209 @ExpectedClassFlags("[FINAL, IDENTITY]") 210 /*package*/ final identity class TestFinalIdentityClass {} 211 212 @ExpectedClassFlags("[IDENTITY, ABSTRACT]") 213 /*package*/ abstract class TestAbstractClass {} 214 @ExpectedClassFlags("[IDENTITY, ABSTRACT]") 215 /*package*/ abstract identity class TestAbstractIdentityClass {} 216 217 @ExpectedClassFlags("[STATIC, INTERFACE, ABSTRACT, ANNOTATION]") 218 /*package*/ @interface TestMarkerAnnotation {} 219 220 @ExpectedClassFlags("[PUBLIC, STATIC, FINAL, IDENTITY, ENUM]") 221 public enum MetaSynVar { 222 QUUX; 223 } 224 225 // Is there is at least one special enum constant, the enum class 226 // itself is implicitly abstract rather than final. 227 @ExpectedClassFlags("[PROTECTED, STATIC, IDENTITY, ABSTRACT, ENUM]") 228 protected enum MetaSynVar2 { 229 WOMBAT{ 230 @Override 231 public int foo() {return 42;} 232 }; 233 public abstract int foo(); 234 } 235 236 @ExpectedClassFlags("[PRIVATE, IDENTITY, ABSTRACT]") 237 private abstract class Foo {} 238 @ExpectedClassFlags("[PRIVATE, IDENTITY, ABSTRACT]") 239 private abstract identity class IdentityFoo {} 240 241 @ExpectedClassFlags("[STATIC, INTERFACE, ABSTRACT]") 242 interface StaticTestInterface {} 243 @ExpectedClassFlags("[STATIC, IDENTITY, INTERFACE, ABSTRACT]") 244 identity interface StaticTestIdentityInterface {} 245 @ExpectedClassFlags("[STATIC, VALUE, INTERFACE, ABSTRACT]") 246 value interface StaticTestValueInterface {} 247 } 248 249 @Retention(RetentionPolicy.RUNTIME) 250 @ExpectedClassFlags("[INTERFACE, ABSTRACT, ANNOTATION]") 251 @interface ExpectedClassFlags { 252 String value(); 253 } 254 255 @ExpectedClassFlags("[INTERFACE, ABSTRACT]") 256 interface TestInterface {} 257 @ExpectedClassFlags("[IDENTITY, INTERFACE, ABSTRACT]") 258 identity interface TestIdentityInterface {} 259 @ExpectedClassFlags("[VALUE, INTERFACE, ABSTRACT]") 260 value interface TestValueInterface {} 261 262 263 @ExpectedClassFlags("[FINAL, IDENTITY, ENUM]") 264 enum TestOuterEnum { 265 INSTANCE; 266 }