1 /* 2 * Copyright (c) 2020, 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 8242013 27 * @run testng/othervm test.TypeDescriptorTest 28 * @summary Test TypeDescriptor::descriptorString for hidden classes which 29 * cannot be used to produce ConstantDesc via ClassDesc or 30 * MethodTypeDesc factory methods 31 */ 32 33 package test; 34 35 import java.io.IOException; 36 import java.io.UncheckedIOException; 37 import java.lang.constant.*; 38 import java.lang.invoke.*; 39 import java.lang.invoke.MethodHandles.Lookup; 40 import java.lang.reflect.Array; 41 import java.nio.file.Files; 42 import java.nio.file.Paths; 43 import static java.lang.invoke.MethodType.*; 44 45 import org.testng.annotations.Test; 46 import org.testng.annotations.DataProvider; 47 import static org.testng.Assert.*; 48 49 public class TypeDescriptorTest { 50 private static final Lookup HC_LOOKUP = defineHiddenClass(); 51 private static final Class<?> HC = HC_LOOKUP.lookupClass(); 52 private static Lookup defineHiddenClass() { 53 String classes = System.getProperty("test.classes"); 54 try { 55 byte[] bytes = Files.readAllBytes(Paths.get(classes, "test/HiddenClass.class")); 56 return MethodHandles.lookup().defineHiddenClass(bytes, true); 57 } catch (IOException e) { 58 throw new UncheckedIOException(e); 59 } catch (IllegalAccessException e) { 60 throw new RuntimeException(e); 61 } 62 } 63 64 @DataProvider(name = "constables") 65 private Object[][] constables() throws Exception { 66 Class<?> hcArray = Array.newInstance(HC, 1).getClass(); 67 return new Object[][] { 68 new Object[] { HC }, 69 new Object[] { hcArray }, 70 new Object[] { methodType(HC) }, 71 new Object[] { methodType(void.class, HC) }, 72 new Object[] { methodType(void.class, HC, int.class) }, 73 new Object[] { HC_LOOKUP.findStatic(HC, "m", methodType(void.class)) }, 74 new Object[] { HC_LOOKUP.findStaticVarHandle(HC, "f", Object.class) } 75 }; 76 } 77 78 /* 79 * Hidden classes have no nominal descriptor. 80 * Constable::describeConstable returns empty optional. 81 */ 82 @Test(dataProvider = "constables") 83 public void noNominalDescriptor(Constable constable) { 84 assertTrue(constable.describeConstable().isEmpty()); 85 } 86 87 /* 88 * ClassDesc factory methods throws IAE with the name or descriptor string 89 * from a hidden class 90 */ 91 @Test 92 public void testClassDesc() { 93 try { 94 ClassDesc.ofDescriptor(HC.descriptorString()); 95 assertFalse(true); 96 } catch (IllegalArgumentException e) {} 97 98 try { 99 ClassDesc.ofDescriptor(HC.getName()); 100 assertFalse(true); 101 } catch (IllegalArgumentException e) {} 102 try { 103 ClassDesc.of(HC.getPackageName(), HC.getSimpleName()); 104 assertFalse(true); 105 } catch (IllegalArgumentException e) {} 106 try { 107 ClassDesc.of(HC.getName()); 108 assertFalse(true); 109 } catch (IllegalArgumentException e) {} 110 } 111 112 @DataProvider(name = "typeDescriptors") 113 private Object[][] typeDescriptors() throws Exception { 114 Class<?> hcArray = Array.newInstance(HC, 1, 1).getClass(); 115 return new Object[][] { 116 new Object[] { HC, "Ltest/HiddenClass.0x[0-9a-f]+;"}, 117 new Object[] { hcArray, "\\[\\[Ltest/HiddenClass.0x[0-9a-f]+;"}, 118 new Object[] { methodType(HC), "\\(\\)Ltest/HiddenClass.0x[0-9a-f]+;" }, 119 new Object[] { methodType(void.class, HC), "\\(Ltest/HiddenClass.0x[0-9a-f]+;\\)V" }, 120 new Object[] { methodType(void.class, HC, int.class, Object.class), "\\(Ltest/HiddenClass.0x[0-9a-f]+;ILjava/lang/Object;\\)V" } 121 }; 122 } 123 124 /* 125 * Hidden classes have no nominal type descriptor 126 */ 127 @Test(dataProvider = "typeDescriptors") 128 public void testTypeDescriptor(TypeDescriptor td, String regex) throws Exception { 129 String desc = td.descriptorString(); 130 assertTrue(desc.matches(regex)); 131 132 if (td instanceof Class) { 133 try { 134 ClassDesc.ofDescriptor(desc); 135 assertFalse(true); 136 } catch (IllegalArgumentException e) {} 137 } else if (td instanceof MethodType) { 138 try { 139 MethodTypeDesc.ofDescriptor(desc); 140 assertFalse(true); 141 } catch (IllegalArgumentException e) {} 142 } 143 } 144 145 @DataProvider(name = "methodTypes") 146 private Object[][] methodTypes() throws Exception { 147 Class<?> hcArray = Array.newInstance(HC, 1, 1).getClass(); 148 return new Object[][] { 149 new Object[] { methodType(HC), "\\(\\)Ltest/HiddenClass.0x[0-9a-f]+;" }, 150 new Object[] { methodType(void.class, hcArray), "\\(\\[\\[Ltest/HiddenClass.0x[0-9a-f]+;\\)V" }, 151 new Object[] { methodType(void.class, int.class, HC), "\\(ILtest/HiddenClass.0x[0-9a-f]+;\\)V" } 152 }; 153 } 154 155 /* 156 * Test MethodType::toMethodDescriptorString with MethodType referencing to hidden class 157 */ 158 @Test(dataProvider = "methodTypes") 159 public void testToMethodDescriptorString(MethodType mtype, String regex) throws Exception { 160 String desc = mtype.toMethodDescriptorString(); 161 assertTrue(desc.matches(regex)); 162 163 try { 164 MethodType.fromMethodDescriptorString(desc, TypeDescriptorTest.class.getClassLoader()); 165 assertFalse(true); 166 } catch (IllegalArgumentException e) {} 167 } 168 } 169 170 class HiddenClass { 171 private static final Object f = new Object(); 172 public static void m() { 173 } 174 }