1 /* 2 * Copyright (c) 2022, 2025, 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 import static java.lang.reflect.AccessFlag.*; 35 36 /* 37 * Class access flags that can directly or indirectly declared in 38 * source include: 39 * public, private, protected, static, final, interface, abstract, 40 * annotation, enum. 41 * 42 * Additionally, the access flags super and synthetic cannot be 43 * explicitly applied. 44 * 45 * This test is written on top of the facilities of core reflection. 46 * 47 * Note that core reflection does not offer a supported mechanism to 48 * return the Class object created from a module-info.class 49 * file. Therefore, this test does not attempt to probe the setting of 50 * that access flag. 51 */ 52 @ExpectedClassFlags({PUBLIC, FINAL, SUPER}) 53 public final class ClassAccessFlagTest { 54 public static void main(String... args) { 55 // Top-level and auxiliary classes; i.e. non-inner classes 56 Class<?>[] testClasses = { 57 ClassAccessFlagTest.class, 58 TestInterface.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 Set<AccessFlag> base = EnumSet.noneOf(AccessFlag.class); 82 Collections.addAll(base, expected.value()); 83 Set<AccessFlag> actual = clazz.accessFlags(); 84 if (!base.equals(actual)) { 85 throw new RuntimeException("On " + clazz + 86 " expected " + base + 87 " got " + actual); 88 } 89 } 90 } 91 92 private static void checkPrimitives() { 93 final Class<?>[] primitives = { 94 byte.class, 95 int.class, 96 long.class, 97 short.class, 98 char.class, 99 float.class, 100 double.class, 101 boolean.class, 102 void.class // same access flag rules 103 }; 104 105 var expected = Set.of(PUBLIC, 106 AccessFlag.FINAL, 107 AccessFlag.ABSTRACT); 108 109 for(var primClass : primitives) { 110 var accessFlags = primClass.accessFlags(); 111 if (!accessFlags.equals(expected)) { 112 throw new RuntimeException("Unexpected flags on " + 113 primClass); 114 } 115 } 116 } 117 118 private static boolean containsAny(Set<AccessFlag> input, 119 Set<AccessFlag> test) { 120 var copy = new HashSet<>(input); 121 return copy.removeAll(test); 122 } 123 124 private static void checkArrays() { 125 Class<?>[] accessClasses = { 126 PublicInterface.class, 127 ProtectedInterface.class, 128 PrivateInterface.class, 129 }; 130 131 for (var accessClass : accessClasses) { 132 AccessFlag accessLevel; 133 var flags = accessClass.accessFlags(); 134 if (flags.contains(PUBLIC)) 135 accessLevel = PUBLIC; 136 else if (flags.contains(AccessFlag.PROTECTED)) 137 accessLevel = AccessFlag.PROTECTED; 138 else if (flags.contains(AccessFlag.PRIVATE)) 139 accessLevel = AccessFlag.PRIVATE; 140 else 141 accessLevel = null; 142 143 var arrayClass = accessClass.arrayType(); 144 // Access modifier must match on the array type 145 if (accessLevel != null) { 146 if (!arrayClass.accessFlags().contains(accessLevel)) { 147 throw new RuntimeException("Mismatched access flags on " + 148 arrayClass); 149 } 150 } else { 151 if (containsAny(arrayClass.accessFlags(), 152 Set.of(PUBLIC, 153 AccessFlag.PROTECTED, 154 AccessFlag.PRIVATE))) { 155 throw new RuntimeException("Unexpected access flags on " + 156 arrayClass); 157 } 158 } 159 } 160 161 } 162 163 // inner classes and interfaces; possible flags on INNER_CLASS 164 // locations: 165 // PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, INTERFACE, ABSTRACT, 166 // SYNTHETIC, ANNOTATION, ENUM. 167 168 @ExpectedClassFlags({PUBLIC, STATIC, INTERFACE, ABSTRACT}) 169 public interface PublicInterface {} 170 @ExpectedClassFlags({PROTECTED, STATIC, INTERFACE, ABSTRACT}) 171 protected interface ProtectedInterface {} 172 @ExpectedClassFlags({PRIVATE, STATIC, INTERFACE, ABSTRACT}) 173 private interface PrivateInterface {} 174 @ExpectedClassFlags({STATIC, INTERFACE, ABSTRACT}) 175 /*package*/ interface PackageInterface {} 176 177 @ExpectedClassFlags({FINAL}) 178 /*package*/ final class TestFinalClass {} 179 180 @ExpectedClassFlags({ABSTRACT}) 181 /*package*/ abstract class TestAbstractClass {} 182 183 @ExpectedClassFlags({STATIC, INTERFACE, ABSTRACT, ANNOTATION}) 184 /*package*/ @interface TestMarkerAnnotation {} 185 186 @ExpectedClassFlags({PUBLIC, STATIC, FINAL, ENUM}) 187 public enum MetaSynVar { 188 QUUX; 189 } 190 191 // Is there is at least one special enum constant, the enum class 192 // itself is implicitly abstract rather than final. 193 @ExpectedClassFlags({PROTECTED, STATIC, ABSTRACT, ENUM}) 194 protected enum MetaSynVar2 { 195 WOMBAT{ 196 @Override 197 public int foo() {return 42;} 198 }; 199 public abstract int foo(); 200 } 201 202 @ExpectedClassFlags({PRIVATE, ABSTRACT}) 203 private abstract class Foo {} 204 205 @ExpectedClassFlags({STATIC, INTERFACE, ABSTRACT}) 206 interface StaticTestInterface {} 207 } 208 209 @Retention(RetentionPolicy.RUNTIME) 210 @ExpectedClassFlags({INTERFACE, ABSTRACT, ANNOTATION}) 211 @interface ExpectedClassFlags { 212 AccessFlag[] value(); 213 } 214 215 @ExpectedClassFlags({INTERFACE, ABSTRACT}) 216 interface TestInterface {} 217 218 219 @ExpectedClassFlags({FINAL, SUPER, ENUM}) 220 enum TestOuterEnum { 221 INSTANCE; 222 }