1 /* 2 * Copyright (c) 2018, 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 core reflection, dynamic proxy and lambdas that generates 27 * classes dynamically that reference Q-type and L-type 28 * @compile -XDallowWithFieldOperator Point.java Line.java MutablePath.java 29 * @compile -XDallowWithFieldOperator NonFlattenValue.java 30 * @run testng/othervm -XX:+EnableValhalla QTypeDescriptorTest 31 * @run testng/othervm -XX:+EnableValhalla -Dsun.reflect.noInflation=true QTypeDescriptorTest 32 */ 33 34 import java.lang.invoke.MethodHandle; 35 import java.lang.invoke.MethodHandles; 36 import java.lang.invoke.MethodType; 37 import java.lang.reflect.*; 38 import java.util.function.*; 39 40 import org.testng.annotations.DataProvider; 41 import org.testng.annotations.Test; 42 import static org.testng.Assert.*; 43 44 public class QTypeDescriptorTest { 45 static final Point P0 = Point.makePoint(10, 20); 46 static final Point P1 = Point.makePoint(30, 40); 47 static final NonFlattenValue NFV = NonFlattenValue.make(30, 40); 48 49 @Test 50 public static void testLambda() { 51 newArray(Point[]::new, 2); 52 newArray(Point[][]::new, 1); 53 54 newArray(NonFlattenValue[]::new, 3); 55 newArray(MutablePath[]::new, 4); 56 57 Function<Point[], T> f = 58 (points) -> { return new T(points); }; 59 f.apply(new Point[] { P0, P1}); 60 } 61 62 @Test 63 public static void testMethodInvoke() throws Exception { 64 Class<?> pointQType = Point.class.asValueType(); 65 Class<?> nonFlattenValueQType = NonFlattenValue.class.asValueType(); 66 Method m = QTypeDescriptorTest.class 67 .getDeclaredMethod("toLine", pointQType, nonFlattenValueQType); 68 makeLine(m, P0, NFV); 69 70 m = QTypeDescriptorTest.class 71 .getDeclaredMethod("toLine", Point[].class); 72 makeLine(m, (Object) new Point[] { P0, P1}); 73 } 74 75 private static void makeLine(Method m, Object... args) throws Exception { 76 Line l = (Line) m.invoke(null, args); 77 assertEquals(l.p1, P0); 78 assertEquals(l.p2, NFV.pointValue()); 79 } 80 81 @Test 82 public static void testStaticMethod() throws Throwable { 83 // static method in an inline type with no parameter and void return type 84 Runnable r = () -> ValueTest.run(); 85 r.run(); 86 87 // via Method::invoke 88 Method m = ValueTest.class.getMethod("run"); 89 m.invoke(null); 90 91 // via MethodHandle 92 MethodHandle mh = MethodHandles.lookup() 93 .findStatic(ValueTest.class, "run", MethodType.methodType(void.class)); 94 mh.invokeExact(); 95 96 mh = MethodHandles.lookup().unreflect(m); 97 mh.invokeExact(); 98 } 99 100 @Test 101 public static void testConstructor() throws Exception { 102 Constructor<T> ctor = T.class.getDeclaredConstructor(Point[].class); 103 Point[] points = new Point[] { P0, P1 }; 104 T test = (T) ctor.newInstance((Object)points); 105 assertEquals(test.points[0], P0); 106 assertEquals(test.points[1], P1); 107 } 108 109 @Test 110 public static void testProxy() throws Exception { 111 InvocationHandler handler = new InvocationHandler() { 112 @Override 113 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 114 if (method.getName().equals("toLine")) { 115 return toLine((Point)args[0], (NonFlattenValue)args[1]); 116 } 117 throw new UnsupportedOperationException(method.toString()); 118 } 119 }; 120 121 Class<?>[] intfs = new Class<?>[] { I.class }; 122 I intf = (I) Proxy.newProxyInstance(QTypeDescriptorTest.class.getClassLoader(), intfs, handler); 123 Line l = intf.toLine(P0, NFV); 124 assertEquals(l.p1, P0); 125 assertEquals(l.p2, NFV.pointValue()); 126 } 127 128 @DataProvider 129 static Object[][] descriptors() { 130 Class<?> pointLType = Point.class.asBoxType(); 131 Class<?> pointQType = Point.class.asValueType(); 132 Class<?> nonFlattenValueLType = NonFlattenValue.class.asBoxType(); 133 Class<?> nonFlattenValueQType = NonFlattenValue.class.asValueType(); 134 return new Object[][]{ 135 { QTypeDescriptorTest.class, "toLine", new Class<?>[] {pointQType, nonFlattenValueQType}, true}, 136 { QTypeDescriptorTest.class, "toLine", new Class<?>[] {pointLType, nonFlattenValueQType}, false}, 137 { QTypeDescriptorTest.class, "toLine", new Class<?>[] { Point[].class }, true}, 138 { NonFlattenValue.class, "point", null, true}, 139 { NonFlattenValue.class, "pointValue", null, true}, 140 { NonFlattenValue.class, "has", new Class<?>[] {pointQType, pointLType}, true}, 141 { NonFlattenValue.class, "has", new Class<?>[] {pointQType, pointQType}, false}, 142 }; 143 } 144 145 @Test(dataProvider = "descriptors") 146 public static void testDescriptors(Class<?> defc, String name, Class<?>[] params, boolean found) throws Exception { 147 try { 148 defc.getDeclaredMethod(name, params); 149 if (!found) throw new AssertionError("Expected NoSuchMethodException"); 150 } catch (NoSuchMethodException e) { 151 if (found) throw e; 152 } 153 } 154 155 @DataProvider 156 static Object[][] methodTypes() { 157 Class<?> pointLType = Point.class.asBoxType(); 158 Class<?> pointQType = Point.class.asValueType(); 159 ClassLoader loader = QTypeDescriptorTest.class.getClassLoader(); 160 return new Object[][]{ 161 { "point", MethodType.methodType(pointLType), true }, 162 { "pointValue", MethodType.methodType(pointQType), true }, 163 { "has", MethodType.methodType(boolean.class, pointQType, pointLType), true }, 164 { "point", MethodType.methodType(pointQType), false }, 165 { "pointValue", MethodType.methodType(pointLType), false }, 166 { "has", MethodType.methodType(boolean.class, pointLType, pointQType), false }, 167 { "point", MethodType.fromMethodDescriptorString("()LPoint;", loader), true }, 168 { "point", MethodType.fromMethodDescriptorString("()QPoint;", loader), false }, 169 { "pointValue", MethodType.fromMethodDescriptorString("()QPoint;", loader), true }, 170 { "pointValue", MethodType.fromMethodDescriptorString("()LPoint;", loader), false }, 171 { "has", MethodType.fromMethodDescriptorString("(QPoint;LPoint;)Z", loader), true }, 172 { "has", MethodType.fromMethodDescriptorString("(LPoint;LPoint;)Z", loader), false }, 173 }; 174 } 175 176 @Test(dataProvider = "methodTypes") 177 public static void methodHandleLookup(String name, MethodType mtype, boolean found) throws Throwable { 178 try { 179 MethodHandles.lookup().findVirtual(NonFlattenValue.class, name, mtype); 180 if (!found) throw new AssertionError("Expected NoSuchMethodException"); 181 } catch (NoSuchMethodException e) { 182 if (found) throw e; 183 } 184 } 185 186 private static <T> T[] newArray(IntFunction<T[]> arrayCreator, int size) { 187 return arrayCreator.apply(size); 188 } 189 190 private static Line toLine(Point p, NonFlattenValue nfv) { 191 return Line.makeLine(p, nfv.pointValue()); 192 } 193 194 private static Line toLine(Point[] points) { 195 assertTrue(points.length == 2); 196 return Line.makeLine(points[0], points[1]); 197 } 198 199 static class T { 200 final Point[] points; 201 T(Point[] points) { 202 this.points = points; 203 } 204 } 205 206 interface I { 207 Line toLine(Point p, NonFlattenValue nfv); 208 } 209 210 static inline class ValueTest { 211 private final int value; 212 public ValueTest() { this.value = 0; } 213 214 public static void run() { 215 Runnable r = () -> { 216 System.out.println("called ValueTest::run"); 217 }; 218 r.run(); 219 } 220 } 221 222 }