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 }