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 return new Object[][] { 67 new Object[] { HC }, 68 new Object[] { methodType(HC) }, 69 new Object[] { methodType(void.class, HC) }, 70 new Object[] { methodType(void.class, HC, int.class) }, 71 new Object[] { HC_LOOKUP.findStatic(HC, "m", methodType(void.class)) }, 72 new Object[] { HC_LOOKUP.findStaticVarHandle(HC, "f", Object.class) } 73 }; 74 } 75 76 /* 77 * Hidden classes have no nominal descriptor. 78 * Constable::describeConstable returns empty optional. 79 */ 80 @Test(dataProvider = "constables") 81 public void noNominalDescriptor(Constable constable) { 82 assertTrue(constable.describeConstable().isEmpty()); 83 } 84 85 /* 86 * ClassDesc factory methods throws IAE with the name or descriptor string 87 * from a hidden class 88 */ 89 @Test 90 public void testClassDesc() { 91 try { 92 ClassDesc.ofDescriptor(HC.descriptorString()); 93 assertFalse(true); 94 } catch (IllegalArgumentException e) { 95 System.out.println(e.getClass().getName() + " " + e.getMessage()); 96 } 97 98 try { 99 ClassDesc.ofDescriptor(HC.getName()); 100 assertFalse(true); 101 } catch (IllegalArgumentException e) { 102 System.out.println(e.getClass().getName() + " " + e.getMessage()); 103 } 104 try { 105 ClassDesc.of(HC.getPackageName(), HC.getSimpleName()); 106 assertFalse(true); 107 } catch (IllegalArgumentException e) { 108 System.out.println(e.getClass().getName() + " " + e.getMessage()); 109 } 110 try { 111 ClassDesc.of(HC.getName()); 112 assertFalse(true); 113 } catch (IllegalArgumentException e) { 114 System.out.println(e.getClass().getName() + " " + e.getMessage()); 115 } 116 } 117 118 @DataProvider(name = "typeDescriptors") 119 private Object[][] typeDescriptors() throws Exception { 120 Class<?> hcArray = Array.newInstance(HC, 1, 1).getClass(); 121 return new Object[][] { 122 new Object[] { HC, "Ltest/HiddenClass.0x[0-9a-f]+;"}, 123 new Object[] { hcArray, "\\[\\[Ltest/HiddenClass.0x[0-9a-f]+;"}, 124 new Object[] { methodType(HC), "\\(\\)Ltest/HiddenClass.0x[0-9a-f]+;" }, 125 new Object[] { methodType(void.class, HC), "\\(Ltest/HiddenClass.0x[0-9a-f]+;\\)V" }, 126 new Object[] { methodType(void.class, HC, int.class, Object.class), "\\(Ltest/HiddenClass.0x[0-9a-f]+;ILjava/lang/Object;\\)V" } 127 }; 128 } 129 130 /* 131 * Hidden classes have no nominal type descriptor 132 */ 133 @Test(dataProvider = "typeDescriptors") 134 public void testTypeDescriptor(TypeDescriptor td, String regex) throws Exception { 135 String desc = td.descriptorString(); 136 System.out.println(desc + " " + desc.matches(regex)); 137 assertTrue(desc.matches(regex)); 138 139 if (td instanceof Class) { 140 try { 141 ClassDesc.ofDescriptor(desc); 142 assertFalse(true); 143 } catch (IllegalArgumentException e) { 144 System.out.println(e.getClass().getName() + " " + e.getMessage()); 145 } 146 } else if (td instanceof MethodType) { 147 try { 148 MethodTypeDesc.ofDescriptor(desc); 149 assertFalse(true); 150 } catch (IllegalArgumentException e) { 151 System.out.println(e.getClass().getName() + " " + e.getMessage()); 152 } 153 } 154 } 155 156 @DataProvider(name = "methodTypes") 157 private Object[][] methodTypes() throws Exception { 158 Class<?> hcArray = Array.newInstance(HC, 1, 1).getClass(); 159 return new Object[][] { 160 new Object[] { methodType(HC), "\\(\\)Ltest/HiddenClass.0x[0-9a-f]+;" }, 161 new Object[] { methodType(void.class, hcArray), "\\(\\[\\[Ltest/HiddenClass.0x[0-9a-f]+;\\)V" }, 162 new Object[] { methodType(void.class, int.class, HC), "\\(ILtest/HiddenClass.0x[0-9a-f]+;\\)V" } 163 }; 164 } 165 166 /* 167 * Test MethodType::toMethodDescriptorString with MethodType referencing to hidden class 168 */ 169 @Test(dataProvider = "methodTypes") 170 public void testToMethodDescriptorString(MethodType mtype, String regex) throws Exception { 171 String desc = mtype.toMethodDescriptorString(); 172 assertTrue(desc.matches(regex)); 173 174 try { 175 MethodType.fromMethodDescriptorString(desc, TypeDescriptorTest.class.getClassLoader()); 176 } catch (IllegalArgumentException e) { 177 System.out.println("not-well formed: " + desc); 178 } 179 } 180 } 181 182 class HiddenClass { 183 private static final Object f = new Object(); 184 public static void m() { 185 } 186 }