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