1 /* 2 * Copyright (c) 2017, 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 /* 26 * @test 27 * @summary test reflection on inline types 28 * @compile -XDallowWithFieldOperator Point.java Line.java NonFlattenValue.java 29 * @run main/othervm -XX:+EnableValhalla Reflection 30 */ 31 32 import java.lang.reflect.Array; 33 import java.lang.reflect.Constructor; 34 import java.lang.reflect.Field; 35 import java.lang.reflect.InaccessibleObjectException; 36 import java.lang.reflect.Method; 37 import java.lang.reflect.Modifier; 38 import java.util.Arrays; 39 import java.util.List; 40 import java.util.stream.Collectors; 41 42 public class Reflection { 43 public static void main(String... args) throws Exception { 44 testPointClass(); 45 testLineClass(); 46 testNonFlattenValue(); 47 testMirrors(); 48 testClassName(); 49 } 50 51 static void testPointClass() throws Exception { 52 Point o = Point.makePoint(10, 20); 53 Reflection test = new Reflection(Point.class, "Point", o); 54 test.newInstance(); 55 test.constructor(); 56 test.constructors("public Point(int,int)", "Point()"); 57 test.accessFieldX(o.x); 58 test.setAccessible(); 59 test.trySetAccessible(); 60 test.staticField(); 61 test.initFactoryNotMethods(); 62 } 63 64 static void testLineClass() throws Exception { 65 Line l = Line.makeLine(10, 20, 30, 40); 66 Reflection test = new Reflection(Line.class, "Line", l); 67 test.checkField("public final Point Line.p1", "p1", Point.class); 68 test.checkField("public final Point Line.p2", "p2", Point.class); 69 test.checkMethod("public Point Line.p1()", "p1", Point.class); 70 test.checkMethod("public Point Line.p2()", "p2", Point.class); 71 test.initFactoryNotMethods(); 72 test.constructors("Line()"); 73 } 74 75 static void testNonFlattenValue() throws Exception { 76 NonFlattenValue nfv = NonFlattenValue.make(10, 20); 77 Reflection test = new Reflection(NonFlattenValue.class, "NonFlattenValue", nfv); 78 test.checkField("final Point? NonFlattenValue.nfp", "nfp", Point.class.asNullableType()); 79 test.checkMethod("public Point NonFlattenValue.pointValue()", "pointValue", Point.class); 80 test.checkMethod("public Point? NonFlattenValue.point()", "point", Point.class.asNullableType()); 81 test.checkMethod("public boolean NonFlattenValue.has(Point,Point?)", "has", boolean.class, Point.class, Point.class.asNullableType()); 82 test.initFactoryNotMethods(); 83 test.constructors("NonFlattenValue()"); 84 85 } 86 87 /* 88 * Tests reflection APIs with the primary and nullable mirror 89 */ 90 static void testMirrors() throws Exception { 91 Class<?> primary = Point.class; 92 Class<?> nullable = Point.class.asNullableType(); 93 94 assertEquals(primary, Point.class); 95 assertTrue(primary.isInlineClass()); 96 assertTrue(nullable.isInlineClass()); 97 98 Point o = Point.makePoint(10, 20); 99 assertTrue(primary.isInstance(o)); 100 assertTrue(nullable.isInstance(o)); 101 102 // V <: V? and V <: Object 103 assertTrue(nullable.isAssignableFrom(primary)); 104 assertTrue(Object.class.isAssignableFrom(primary)); 105 assertFalse(primary.isAssignableFrom(nullable)); 106 assertTrue(Object.class.isAssignableFrom(nullable)); 107 108 assertEquals(primary, primary.asSubclass(nullable)); 109 try { 110 Class<?> c = nullable.asSubclass(primary); 111 assertTrue(false); 112 } catch (ClassCastException e) { } 113 } 114 115 static void testClassName() { 116 assertEquals(Point.class.getName(), "Point"); 117 assertEquals(Point.class.asNullableType().getName(), "Point"); 118 assertEquals(Line.class.getName(), "Line"); 119 assertEquals((new Point[0]).getClass().getName(), "[QPoint;"); 120 assertEquals((new Point?[0][0]).getClass().getName(), "[[LPoint;"); 121 } 122 123 private final Class<?> c; 124 private final Constructor<?> ctor; 125 private final Object o; 126 Reflection(Class<?> type, String cn, Object o) throws Exception { 127 this.c = Class.forName(cn); 128 if (!c.isInlineClass() || c != type) { 129 throw new RuntimeException(cn + " is not an inline class"); 130 } 131 132 // V.class, Class.forName, and the type of the object return the primary mirror 133 assertEquals(type, o.getClass()); 134 assertEquals(type, c.asPrimaryType()); 135 assertEquals(c, c.asPrimaryType()); 136 137 this.ctor = c.getDeclaredConstructor(); 138 this.o = o; 139 140 141 // test the primary mirror and secondary mirror 142 testMirrors(this.c); 143 // test array of Q-type and L-type 144 testArray(c.asPrimaryType()); 145 testArray(c.asNullableType()); 146 } 147 148 private static void testMirrors(Class<?> c) { 149 Class<?> inlineType = c.asPrimaryType(); 150 Class<?> nullableType = c.asNullableType(); 151 152 assertTrue(inlineType != null); 153 assertEquals(nullableType.getTypeName(), c.getTypeName() + "?"); 154 155 assertEquals(nullableType.getName(), inlineType.getName()); 156 assertEquals(nullableType.getTypeName(), inlineType.getTypeName() + "?"); 157 assertEquals(inlineType.asNullableType(), nullableType); 158 assertEquals(nullableType.asPrimaryType(), inlineType); 159 } 160 161 void testArray(Class<?> elementType) { 162 Object[] array = (Object[])Array.newInstance(elementType, 1); 163 Class<?> arrayType = array.getClass(); 164 assertTrue(arrayType.isArray()); 165 Class<?> componentType = arrayType.getComponentType(); 166 assertTrue(componentType.isInlineClass()); 167 assertEquals(componentType, elementType); 168 // Array is a reference type 169 assertEquals(arrayType.asNullableType(), arrayType); 170 if (array[0] == null) { 171 System.out.println("array[0] = null"); 172 } else { 173 System.out.println("array[0] = " + array[0]); 174 } 175 } 176 177 void accessFieldX(int x) throws Exception { 178 Field field = c.getField("x"); 179 if (field.getInt(o) != x) { 180 throw new RuntimeException("Unexpected Point.x value: " + field.getInt(o)); 181 } 182 183 try { 184 field.setInt(o, 100); 185 throw new RuntimeException("IllegalAccessException not thrown"); 186 } catch (IllegalAccessException e) {} 187 } 188 189 @SuppressWarnings("deprecation") 190 void newInstance() throws Exception { 191 Object o = c.newInstance(); 192 assertEquals(o.getClass(), c); 193 } 194 195 void constructor() throws Exception { 196 Object o = ctor.newInstance(); 197 assertEquals(o.getClass(), c); 198 } 199 200 // Check that the class has the expected Constructors 201 void constructors(String... expected) throws Exception { 202 Constructor<? extends Object>[] cons = c.getDeclaredConstructors(); 203 List<String> declaredSig = Arrays.stream(cons).map( Constructor::toString).collect(Collectors.toList()); 204 List<String> expectedSig = List.of(expected); 205 boolean ok = expectedSig.equals(declaredSig); 206 if (!ok) { 207 System.out.printf("expected: %s%n", expectedSig); 208 System.out.printf("declared: %s%n", declaredSig); 209 assertTrue(ok); 210 } 211 } 212 213 void setAccessible() throws Exception { 214 ctor.setAccessible(true); 215 Field field = c.getField("x"); 216 try { 217 field.setAccessible(true); 218 throw new RuntimeException("InaccessibleObjectException not thrown"); 219 } catch (InaccessibleObjectException e) { 220 System.out.println("as expected: " + e.toString()); 221 } 222 } 223 224 void trySetAccessible() throws Exception { 225 ctor.trySetAccessible(); 226 Field field = c.getField("x"); 227 if (field.trySetAccessible()) { 228 throw new RuntimeException("trySetAccessible should not succeed"); 229 } 230 } 231 232 void staticField() throws Exception { 233 Field f = c.getDeclaredField("STATIC_FIELD"); 234 if (f.trySetAccessible()) { 235 throw new RuntimeException("trySetAccessible should not succeed"); 236 } 237 try { 238 f.setAccessible(true); 239 throw new RuntimeException("IllegalAccessException not thrown"); 240 } catch (InaccessibleObjectException e) { } 241 } 242 243 void checkField(String source, String name, Class<?> type) throws Exception { 244 Field f = c.getDeclaredField(name); 245 assertEquals(f.getType(), type); 246 assertEquals(f.toString(), source); 247 } 248 249 void checkMethod(String source, String name, Class<?> returnType, Class<?>... params) throws Exception { 250 Method m = c.getDeclaredMethod(name, params); 251 assertEquals(m.toString(), source); 252 } 253 254 // Check that the class does not have a static method with the name <init> 255 void initFactoryNotMethods() throws Exception { 256 Method[] methods = c.getDeclaredMethods(); 257 for (Method m : methods) { 258 if (Modifier.isStatic(m.getModifiers())) { 259 assertFalse(m.getName().equals("<init>")); 260 } 261 } 262 } 263 264 static void assertEquals(Object o1, Object o2) { 265 if (o1 == o2 || o1.equals(o2)) 266 return; 267 268 throw new AssertionError(o1 + " != " + o2); 269 } 270 271 static void assertTrue(boolean value) { 272 if (!value) 273 throw new AssertionError("expected true"); 274 } 275 276 static void assertFalse(boolean value) { 277 if (value) 278 throw new AssertionError("expected false"); 279 } 280 }