22 */
23
24 /*
25 * @test
26 * @bug 8330467
27 * @modules jdk.compiler
28 * @library /test/lib
29 * @compile BadClassFile.jcod
30 * BadClassFile2.jcod
31 * BadClassFileVersion.jcod
32 * @build jdk.test.lib.Utils
33 * jdk.test.lib.compiler.CompilerUtils
34 * @run junit/othervm BasicTest
35 */
36
37 import java.io.File;
38 import java.io.IOException;
39 import java.lang.classfile.ClassFile;
40 import java.lang.constant.ClassDesc;
41 import java.lang.invoke.MethodHandles.Lookup;
42 import java.lang.reflect.Array;
43 import java.lang.reflect.Method;
44 import java.nio.charset.StandardCharsets;
45 import java.nio.file.Files;
46 import java.nio.file.Path;
47 import java.nio.file.Paths;
48 import java.util.Arrays;
49 import java.util.List;
50 import java.util.stream.Stream;
51
52 import jdk.test.lib.compiler.CompilerUtils;
53 import jdk.test.lib.Utils;
54
55 import static java.lang.classfile.ClassFile.*;
56 import static java.lang.constant.ConstantDescs.CD_Enum;
57 import static java.lang.constant.ConstantDescs.CD_Object;
58 import static java.lang.invoke.MethodHandles.lookup;
59 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
60 import static org.junit.jupiter.api.Assertions.*;
61 import org.junit.jupiter.api.BeforeAll;
97
98 static Class<?> defineHiddenClass(String name) throws Exception {
99 byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve(name + ".class"));
100 Class<?> hc = lookup().defineHiddenClass(bytes, false).lookupClass();
101 assertHiddenClass(hc);
102 singletonNest(hc);
103 return hc;
104 }
105
106 // basic test on a hidden class
107 @Test
108 public void hiddenClass() throws Throwable {
109 HiddenTest t = (HiddenTest)defineHiddenClass("HiddenClass").newInstance();
110 t.test();
111
112 // sanity check
113 Class<?> c = t.getClass();
114 Class<?>[] intfs = c.getInterfaces();
115 assertTrue(c.isHidden());
116 assertFalse(c.isPrimitive());
117 assertEquals(1, intfs.length);
118 assertSame(HiddenTest.class, intfs[0]);
119 assertNull(c.getCanonicalName());
120
121 String hcName = "HiddenClass";
122 String hcSuffix = "0x[0-9a-f]+";
123 assertTrue(c.getName().matches(hcName + "/" + hcSuffix));
124 assertTrue(c.descriptorString().matches("L" + hcName + "." + hcSuffix + ";"), c.descriptorString());
125
126 // test array of hidden class
127 testHiddenArray(c);
128
129 // test setAccessible
130 checkSetAccessible(c, "realTest");
131 checkSetAccessible(c, "test");
132 }
133
134 // primitive class is not a hidden class
135 @Test
136 public void primitiveClass() {
137 assertFalse(int.class.isHidden());
138 assertFalse(String.class.isHidden());
232 @ParameterizedTest
233 @MethodSource("hiddenClasses")
234 public void defineHiddenClass(String name, boolean nestmate) throws Exception {
235 byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve(name + ".class"));
236 Class<?> hc;
237 Class<?> host;
238 if (nestmate) {
239 hc = lookup().defineHiddenClass(bytes, false, NESTMATE).lookupClass();
240 host = lookup().lookupClass().getNestHost();
241 } else {
242 hc = lookup().defineHiddenClass(bytes, false).lookupClass();
243 host = hc;
244 }
245 assertSame(host, hc.getNestHost());
246 assertEquals(1, hc.getNestMembers().length);
247 assertSame(host, hc.getNestMembers()[0]);
248 }
249
250 private static Object[][] emptyClasses() {
251 return new Object[][] {
252 new Object[] { "EmptyHiddenSynthetic", ACC_SYNTHETIC },
253 new Object[] { "EmptyHiddenEnum", ACC_ENUM },
254 new Object[] { "EmptyHiddenAbstractClass", ACC_ABSTRACT },
255 new Object[] { "EmptyHiddenInterface", ACC_ABSTRACT|ACC_INTERFACE },
256 new Object[] { "EmptyHiddenAnnotation", ACC_ANNOTATION|ACC_ABSTRACT|ACC_INTERFACE },
257 };
258 }
259
260 /*
261 * Test if an empty class with valid access flags can be created as a hidden class
262 * as long as it does not violate the restriction of a hidden class.
263 *
264 * A meaningful enum type defines constants of that enum type. So
265 * enum class containing constants of its type should not be a hidden
266 * class.
267 */
268 @ParameterizedTest
269 @MethodSource("emptyClasses")
270 public void emptyHiddenClass(String name, int accessFlags) throws Exception {
271 byte[] bytes = (accessFlags == ACC_ENUM) ? classBytes(name, CD_Enum, accessFlags)
272 : classBytes(name, accessFlags);
273 Class<?> hc = lookup().defineHiddenClass(bytes, false).lookupClass();
274 switch (accessFlags) {
275 case ACC_SYNTHETIC:
276 assertTrue(hc.isSynthetic());
277 assertFalse(hc.isEnum());
278 assertFalse(hc.isAnnotation());
279 assertFalse(hc.isInterface());
280 break;
281 case ACC_ENUM:
282 assertFalse(hc.isSynthetic());
283 assertTrue(hc.isEnum());
284 assertFalse(hc.isAnnotation());
285 assertFalse(hc.isInterface());
286 break;
287 case ACC_ABSTRACT:
288 assertFalse(hc.isSynthetic());
289 assertFalse(hc.isEnum());
290 assertFalse(hc.isAnnotation());
291 assertFalse(hc.isInterface());
292 break;
293 case ACC_ABSTRACT|ACC_INTERFACE:
294 assertFalse(hc.isSynthetic());
295 assertFalse(hc.isEnum());
296 assertFalse(hc.isAnnotation());
297 assertTrue(hc.isInterface());
298 break;
299 case ACC_ANNOTATION|ACC_ABSTRACT|ACC_INTERFACE:
300 assertFalse(hc.isSynthetic());
301 assertFalse(hc.isEnum());
302 assertTrue(hc.isAnnotation());
303 assertTrue(hc.isInterface());
304 break;
305 default:
306 throw new IllegalArgumentException("unexpected access flag: " + accessFlags);
307 }
308 assertTrue(hc.isHidden());
309 assertEquals(hc.getModifiers(), ACC_PUBLIC | accessFlags);
310 assertFalse(hc.isLocalClass());
311 assertFalse(hc.isMemberClass());
312 assertFalse(hc.isAnonymousClass());
313 assertFalse(hc.isArray());
314 }
315
316 // These class files can't be defined as hidden classes
317 private static Object[][] cantBeHiddenClasses() {
318 return new Object[][] {
319 // a hidden class can't be a field's declaring type
320 // enum class with static final HiddenEnum[] $VALUES:
321 new Object[] { "HiddenEnum" },
322 // supertype of this class is a hidden class
323 new Object[] { "HiddenSuper" },
324 // a record class whose equals(HiddenRecord, Object) method
325 // refers to a hidden class in the parameter type and fails
326 // verification. Perhaps this method signature should be reconsidered.
327 new Object[] { "HiddenRecord" },
328 };
329 }
|
22 */
23
24 /*
25 * @test
26 * @bug 8330467
27 * @modules jdk.compiler
28 * @library /test/lib
29 * @compile BadClassFile.jcod
30 * BadClassFile2.jcod
31 * BadClassFileVersion.jcod
32 * @build jdk.test.lib.Utils
33 * jdk.test.lib.compiler.CompilerUtils
34 * @run junit/othervm BasicTest
35 */
36
37 import java.io.File;
38 import java.io.IOException;
39 import java.lang.classfile.ClassFile;
40 import java.lang.constant.ClassDesc;
41 import java.lang.invoke.MethodHandles.Lookup;
42 import java.lang.reflect.AccessFlag;
43 import java.lang.reflect.Array;
44 import java.lang.reflect.Method;
45 import java.nio.charset.StandardCharsets;
46 import java.nio.file.Files;
47 import java.nio.file.Path;
48 import java.nio.file.Paths;
49 import java.util.Arrays;
50 import java.util.List;
51 import java.util.stream.Stream;
52
53 import jdk.test.lib.compiler.CompilerUtils;
54 import jdk.test.lib.Utils;
55
56 import static java.lang.classfile.ClassFile.*;
57 import static java.lang.constant.ConstantDescs.CD_Enum;
58 import static java.lang.constant.ConstantDescs.CD_Object;
59 import static java.lang.invoke.MethodHandles.lookup;
60 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
61 import static org.junit.jupiter.api.Assertions.*;
62 import org.junit.jupiter.api.BeforeAll;
98
99 static Class<?> defineHiddenClass(String name) throws Exception {
100 byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve(name + ".class"));
101 Class<?> hc = lookup().defineHiddenClass(bytes, false).lookupClass();
102 assertHiddenClass(hc);
103 singletonNest(hc);
104 return hc;
105 }
106
107 // basic test on a hidden class
108 @Test
109 public void hiddenClass() throws Throwable {
110 HiddenTest t = (HiddenTest)defineHiddenClass("HiddenClass").newInstance();
111 t.test();
112
113 // sanity check
114 Class<?> c = t.getClass();
115 Class<?>[] intfs = c.getInterfaces();
116 assertTrue(c.isHidden());
117 assertFalse(c.isPrimitive());
118 assertTrue(intfs.length == 1 || intfs.length == 2);
119 assertTrue(intfs[0] == HiddenTest.class || (intfs.length == 2 && intfs[1] == HiddenTest.class));
120 assertNull(c.getCanonicalName());
121
122 String hcName = "HiddenClass";
123 String hcSuffix = "0x[0-9a-f]+";
124 assertTrue(c.getName().matches(hcName + "/" + hcSuffix));
125 assertTrue(c.descriptorString().matches("L" + hcName + "." + hcSuffix + ";"), c.descriptorString());
126
127 // test array of hidden class
128 testHiddenArray(c);
129
130 // test setAccessible
131 checkSetAccessible(c, "realTest");
132 checkSetAccessible(c, "test");
133 }
134
135 // primitive class is not a hidden class
136 @Test
137 public void primitiveClass() {
138 assertFalse(int.class.isHidden());
139 assertFalse(String.class.isHidden());
233 @ParameterizedTest
234 @MethodSource("hiddenClasses")
235 public void defineHiddenClass(String name, boolean nestmate) throws Exception {
236 byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve(name + ".class"));
237 Class<?> hc;
238 Class<?> host;
239 if (nestmate) {
240 hc = lookup().defineHiddenClass(bytes, false, NESTMATE).lookupClass();
241 host = lookup().lookupClass().getNestHost();
242 } else {
243 hc = lookup().defineHiddenClass(bytes, false).lookupClass();
244 host = hc;
245 }
246 assertSame(host, hc.getNestHost());
247 assertEquals(1, hc.getNestMembers().length);
248 assertSame(host, hc.getNestMembers()[0]);
249 }
250
251 private static Object[][] emptyClasses() {
252 return new Object[][] {
253 new Object[] { "EmptyHiddenSynthetic", ACC_SYNTHETIC | ACC_IDENTITY },
254 new Object[] { "EmptyHiddenEnum", ACC_ENUM | ACC_IDENTITY },
255 new Object[] { "EmptyHiddenAbstractClass", ACC_ABSTRACT | ACC_IDENTITY },
256 new Object[] { "EmptyHiddenInterface", ACC_ABSTRACT|ACC_INTERFACE },
257 new Object[] { "EmptyHiddenAnnotation", ACC_ANNOTATION|ACC_ABSTRACT|ACC_INTERFACE },
258 };
259 }
260
261 /*
262 * Test if an empty class with valid access flags can be created as a hidden class
263 * as long as it does not violate the restriction of a hidden class.
264 *
265 * A meaningful enum type defines constants of that enum type. So
266 * enum class containing constants of its type should not be a hidden
267 * class.
268 */
269 @ParameterizedTest
270 @MethodSource("emptyClasses")
271 public void emptyHiddenClass(String name, int accessFlags) throws Exception {
272 byte[] bytes = (accessFlags == (ACC_ENUM | ACC_IDENTITY)) ? classBytes(name, CD_Enum, accessFlags)
273 : classBytes(name, accessFlags);
274 Class<?> hc = lookup().defineHiddenClass(bytes, false).lookupClass();
275 switch (accessFlags) {
276 case (ACC_SYNTHETIC | ACC_IDENTITY):
277 assertTrue(hc.isSynthetic());
278 assertFalse(hc.isEnum());
279 assertFalse(hc.isAnnotation());
280 assertFalse(hc.isInterface());
281 break;
282 case (ACC_ENUM | ACC_IDENTITY):
283 assertFalse(hc.isSynthetic());
284 assertTrue(hc.isEnum());
285 assertFalse(hc.isAnnotation());
286 assertFalse(hc.isInterface());
287 break;
288 case ACC_ABSTRACT | ACC_IDENTITY:
289 assertFalse(hc.isSynthetic());
290 assertFalse(hc.isEnum());
291 assertFalse(hc.isAnnotation());
292 assertFalse(hc.isInterface());
293 break;
294 case ACC_ABSTRACT|ACC_INTERFACE:
295 assertFalse(hc.isSynthetic());
296 assertFalse(hc.isEnum());
297 assertFalse(hc.isAnnotation());
298 assertTrue(hc.isInterface());
299 break;
300 case ACC_ANNOTATION|ACC_ABSTRACT|ACC_INTERFACE:
301 assertFalse(hc.isSynthetic());
302 assertFalse(hc.isEnum());
303 assertTrue(hc.isAnnotation());
304 assertTrue(hc.isInterface());
305 break;
306 default:
307 throw new IllegalArgumentException("unexpected access flag: " + accessFlags);
308 }
309 assertTrue(hc.isHidden());
310 assertEquals(hc.getModifiers(), (ACC_PUBLIC|accessFlags));
311 assertFalse(hc.isLocalClass());
312 assertFalse(hc.isMemberClass());
313 assertFalse(hc.isAnonymousClass());
314 assertFalse(hc.isArray());
315 }
316
317 // These class files can't be defined as hidden classes
318 private static Object[][] cantBeHiddenClasses() {
319 return new Object[][] {
320 // a hidden class can't be a field's declaring type
321 // enum class with static final HiddenEnum[] $VALUES:
322 new Object[] { "HiddenEnum" },
323 // supertype of this class is a hidden class
324 new Object[] { "HiddenSuper" },
325 // a record class whose equals(HiddenRecord, Object) method
326 // refers to a hidden class in the parameter type and fails
327 // verification. Perhaps this method signature should be reconsidered.
328 new Object[] { "HiddenRecord" },
329 };
330 }
|