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, SUPER]") 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 ExpectedClassFlags.class, 58 TestOuterEnum.class 59 }; 60 checkClasses(testClasses); 61 62 // Nested classes of ClassAccessFlagTest 63 checkClasses(ClassAccessFlagTest.class.getDeclaredClasses()); 64 65 checkPrimitives(); 66 checkArrays(); 67 } 68 69 private static void checkClasses(Class<?>[] classes) { 70 for (var clazz : classes) { 71 checkClass(clazz); 72 } 73 } 74 75 private static void checkClass(Class<?> clazz) { 76 ExpectedClassFlags expected = 77 clazz.getAnnotation(ExpectedClassFlags.class); 78 if (expected != null) { 79 String actual = clazz.accessFlags().toString(); 80 if (!expected.value().equals(actual)) { 81 throw new RuntimeException("On " + clazz + 82 " expected " + expected.value() + 83 " got " + actual); 84 } 85 } 86 } 87 88 private static void checkPrimitives() { 89 final Class<?>[] primitives = { 90 byte.class, 91 int.class, 92 long.class, 93 short.class, 94 char.class, 95 float.class, 96 double.class, 97 boolean.class, 98 void.class // same access flag rules 99 }; 100 101 var expected = Set.of(AccessFlag.PUBLIC, 102 AccessFlag.FINAL, 103 AccessFlag.ABSTRACT); 104 105 for(var primClass : primitives) { 106 var accessFlags = primClass.accessFlags(); 107 if (!accessFlags.equals(expected)) { 108 throw new RuntimeException("Unexpected flags on " + 109 primClass); 110 } 111 } 112 } 113 114 private static boolean containsAny(Set<AccessFlag> input, 115 Set<AccessFlag> test) { 116 var copy = new HashSet<>(input); 117 return copy.removeAll(test); 118 } 119 120 private static void checkArrays() { 121 Class<?>[] accessClasses = { 122 PublicInterface.class, 123 ProtectedInterface.class, 124 PrivateInterface.class, 125 }; 126 127 for (var accessClass : accessClasses) { 128 AccessFlag accessLevel; 129 var flags = accessClass.accessFlags(); 130 if (flags.contains(AccessFlag.PUBLIC)) 131 accessLevel = AccessFlag.PUBLIC; 132 else if (flags.contains(AccessFlag.PROTECTED)) 133 accessLevel = AccessFlag.PROTECTED; 134 else if (flags.contains(AccessFlag.PRIVATE)) 135 accessLevel = AccessFlag.PRIVATE; 136 else 137 accessLevel = null; 138 139 var arrayClass = accessClass.arrayType(); 140 // Access modifier must match on the array type 141 if (accessLevel != null) { 142 if (!arrayClass.accessFlags().contains(accessLevel)) { 143 throw new RuntimeException("Mismatched access flags on " + 144 arrayClass); 145 } 146 } else { 147 if (containsAny(arrayClass.accessFlags(), 148 Set.of(AccessFlag.PUBLIC, 149 AccessFlag.PROTECTED, 150 AccessFlag.PRIVATE))) { 151 throw new RuntimeException("Unexpected access flags on " + 152 arrayClass); 153 } 154 } 155 } 156 157 } 158 159 // inner classes and interfaces; possible flags on INNER_CLASS 160 // locations: 161 // PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, INTERFACE, ABSTRACT, 162 // SYNTHETIC, ANNOTATION, ENUM. 163 164 @ExpectedClassFlags("[PUBLIC, STATIC, INTERFACE, ABSTRACT]") 165 public interface PublicInterface {} 166 @ExpectedClassFlags("[PROTECTED, STATIC, INTERFACE, ABSTRACT]") 167 protected interface ProtectedInterface {} 168 @ExpectedClassFlags("[PRIVATE, STATIC, INTERFACE, ABSTRACT]") 169 private interface PrivateInterface {} 170 @ExpectedClassFlags("[STATIC, INTERFACE, ABSTRACT]") 171 /*package*/ interface PackageInterface {} 172 173 @ExpectedClassFlags("[FINAL]") 174 /*package*/ final class TestFinalClass {} 175 176 @ExpectedClassFlags("[ABSTRACT]") 177 /*package*/ abstract class TestAbstractClass {} 178 179 @ExpectedClassFlags("[STATIC, INTERFACE, ABSTRACT, ANNOTATION]") 180 /*package*/ @interface TestMarkerAnnotation {} 181 182 @ExpectedClassFlags("[PUBLIC, STATIC, FINAL, ENUM]") 183 public enum MetaSynVar { 184 QUUX; 185 } 186 187 // Is there is at least one special enum constant, the enum class 188 // itself is implicitly abstract rather than final. 189 @ExpectedClassFlags("[PROTECTED, STATIC, ABSTRACT, ENUM]") 190 protected enum MetaSynVar2 { 191 WOMBAT{ 192 @Override 193 public int foo() {return 42;} 194 }; 195 public abstract int foo(); 196 } 197 198 @ExpectedClassFlags("[PRIVATE, ABSTRACT]") 199 private abstract class Foo {} 200 201 @ExpectedClassFlags("[STATIC, INTERFACE, ABSTRACT]") 202 interface StaticTestInterface {} 203 } 204 205 @Retention(RetentionPolicy.RUNTIME) 206 @ExpectedClassFlags("[INTERFACE, ABSTRACT, ANNOTATION]") 207 @interface ExpectedClassFlags { 208 String value(); 209 } 210 211 @ExpectedClassFlags("[INTERFACE, ABSTRACT]") 212 interface TestInterface {} 213 214 215 @ExpectedClassFlags("[FINAL, SUPER, ENUM]") 216 enum TestOuterEnum { 217 INSTANCE; 218 }