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