1 /*
2 * Copyright (c) 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 * @summary Test JVMTI GetClassModifiers
27 * @modules java.base/jdk.internal.misc
28 * @run junit/othervm/native --enable-native-access=ALL-UNNAMED ${test.main.class}
29 */
30
31 import java.lang.classfile.ClassFile;
32 import java.lang.reflect.Modifier;
33 import java.util.stream.Stream;
34 import jdk.internal.misc.PreviewFeatures;
35
36 import org.junit.jupiter.api.Test;
37 import org.junit.jupiter.params.ParameterizedTest;
38 import org.junit.jupiter.params.provider.MethodSource;
39 import static org.junit.jupiter.api.Assertions.*;
40
41 class GetClassModifiersTest {
42
43 // member classes to test
44
45 public class C1 {}
46 public static class C2 {}
47 public final class C3 {}
48 public static final class C4 {}
49 class C5 {}
50 static class C6 {}
51 final class C7 {}
52 static final class C8 {}
53
54 public abstract class A_C1 {}
55 public static abstract class A_C2 {}
56 abstract class A_C3 {}
57 static abstract class A_C4 {}
58
59 public interface I1 {}
60 interface I2 {}
61
62 public @interface A1 {}
63 @interface A2 {}
64
65 public enum E1 {}
66 enum E2 {}
67
68 public record R1() {}
69 record R2() {}
70
71 static Stream<Class<?>> testClasses() {
72 // local classes
73 class LC {}
74 record LR() {}
75 enum LE {}
76
77 // anonymous class
78 var r = new Runnable() { public void run() {} };
79 Class<?> anonClass = r.getClass();
80
81 return Stream.of(
82 int.class,
83 int[].class,
84 void.class,
85 Object.class,
86 Object[].class,
87 Integer.class,
88 Integer[].class,
89 Void.class,
90 GetClassModifiersTest.class,
91 GetClassModifiersTest[].class,
92 C1.class,
93 C2.class,
94 C3.class,
95 C4.class,
96 C5.class,
97 C6.class,
98 C7.class,
99 C8.class,
100 C1[].class,
101 C2[].class,
102 C3[].class,
103 C4[].class,
104 C5[].class,
105 C6[].class,
106 C7[].class,
107 C8[].class,
108 A_C1.class,
109 A_C2.class,
110 A_C3.class,
111 A_C4.class,
112 A_C1[].class,
113 A_C2[].class,
114 A_C3[].class,
115 A_C4[].class,
116 I1.class,
117 I2.class,
118 I1[].class,
119 I2[].class,
120 A1.class,
121 A2.class,
122 A1[].class,
123 A2[].class,
124 E1.class,
125 E2.class,
126 E1[].class,
127 E2[].class,
128 R1.class,
129 R2.class,
130 R1[].class,
131 R2[].class,
132 LC.class,
133 LR.class,
134 LE.class,
135 LC[].class,
136 LR[].class,
137 LE[].class,
138 anonClass,
139 anonClass.arrayType()
140 );
141 }
142
143 static Stream<Class<?>> primitiveClasses() {
144 return testClasses().filter(Class::isPrimitive);
145 }
146
147 static Stream<Class<?>> arrayClasses() {
148 return testClasses().filter(Class::isArray);
149 }
150
151 /**
152 * Test JVMTI GetClassModifiers implementation. If preview features are enabled then
153 * the JVMTI function should return the same modifiers as Class::getModifiers. If
154 * preview features are disabled then the JVMTI function should preserve long-standing
155 * behavior to return the modifiers with ACC_SUPER set for all calsses except primitive
156 * classes.
157 */
158 @ParameterizedTest
159 @MethodSource("testClasses")
160 void testClass(Class<?> clazz) throws Exception {
161 int expectedModifiers = clazz.getModifiers();
162 if (!clazz.isPrimitive() && !PreviewFeatures.isEnabled()) {
163 expectedModifiers |= ClassFile.ACC_SUPER;
164 }
165 assertEquals(expectedModifiers, jvmtiGetClassModifiers(clazz));
166 }
167
168 /**
169 * Test modifiers specified by JVMTI GetClassModifiers for primitive classes.
170 */
171 @ParameterizedTest
172 @MethodSource("primitiveClasses")
173 void testPrimitiveClass(Class<?> clazz) {
174 assertTrue(clazz.isPrimitive());
175 int mods = jvmtiGetClassModifiers(clazz);
176 assertTrue(Modifier.isPublic(mods));
177 assertFalse(Modifier.isPrivate(mods));
178 assertFalse(Modifier.isProtected(mods));
179 assertTrue(Modifier.isAbstract(mods));
180 assertTrue(Modifier.isFinal(mods));
181 assertFalse(Modifier.isInterface(mods));
182 }
183
184 /**
185 * Test modifiers specified by JVMTI GetClassModifiers for array classes.
186 */
187 @ParameterizedTest
188 @MethodSource("arrayClasses")
189 void testArrayClass(Class<?> clazz) {
190 assertTrue(clazz.isArray());
191 int mods = jvmtiGetClassModifiers(clazz);
192 int componentMods = clazz.getComponentType().getModifiers();
193 assertEquals(Modifier.isPublic(componentMods), Modifier.isPublic(mods));
194 assertEquals(Modifier.isPrivate(componentMods), Modifier.isPrivate(mods));
195 assertEquals(Modifier.isProtected(componentMods), Modifier.isProtected(mods));
196 assertTrue(Modifier.isAbstract(mods));
197 assertTrue(Modifier.isFinal(mods));
198 assertFalse(Modifier.isInterface(mods));
199 }
200
201 private int jvmtiGetClassModifiers(Class<?> clazz) {
202 return GetClassModifiers.getClassModifiers(clazz);
203 }
204 }