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.*; 33 import java.util.Arrays; 34 import java.util.stream.Collectors; 35 36 public class Reflection { 37 public static void main(String... args) throws Exception { 38 testPointClass(); 39 testLineClass(); 40 testNonFlattenValue(); 41 } 42 43 static void testPointClass() throws Exception { 44 Point o = Point.makePoint(10, 20); 45 Reflection test = new Reflection(Point.class, "Point", o); 46 test.newInstance(); 47 test.constructor(); 48 test.accessFieldX(o.x); 49 test.setAccessible(); 50 test.trySetAccessible(); 51 test.staticField(); 52 } 53 54 static void testLineClass() throws Exception { 55 Line l = Line.makeLine(10, 20, 30, 40); 56 Reflection test = new Reflection(Line.class, "Line", l); 57 test.checkField("p1", Point.class.asValueType()); 58 test.checkField("p2", Point.class.asValueType()); 59 test.checkMethod("p1", Point.class.asValueType()); 60 test.checkMethod("p2", Point.class.asValueType()); 61 } 62 63 static void testNonFlattenValue() throws Exception { 64 NonFlattenValue nfv = NonFlattenValue.make(10, 20); 65 Reflection test = new Reflection(NonFlattenValue.class, "NonFlattenValue", nfv); 66 test.checkField("nfp", Point.class.asBoxType()); 67 test.checkMethod("point", Point.class.asBoxType()); 68 test.checkMethod("pointValue", Point.class.asValueType()); 69 test.checkMethod("has", void.class, Point.class.asValueType(), Point.class.asBoxType()); 70 } 71 72 private final Class<?> c; 73 private final Constructor<?> ctor; 74 private final Object o; 75 Reflection(Class<?> type, String cn, Object o) throws Exception { 76 this.c = Class.forName(cn); 77 if (!c.isValue() || c != type) { 78 throw new RuntimeException(cn + " is not an inline class"); 79 } 80 81 // the box type is the primary mirror 82 assertEquals(type, o.getClass()); 83 assertEquals(type, c.asBoxType()); 84 85 this.ctor = c.getDeclaredConstructor(); 86 this.o = o; 87 88 // TODO: what should Object::getClass return? 89 // assertEquals(o.getClass(), c.asValueType()); 90 91 // test the box type and value type 92 testBoxAndValueType(this.c); 93 // test array of Q-type 94 // TODO: array of L-type support 95 testArrayOfQType(); 96 } 97 98 private static void testBoxAndValueType(Class<?> c) { 99 Class<?> box = c.asBoxType(); 100 Class<?> val = c.asValueType(); 101 assertTrue(val != null); 102 assertEquals(box.getTypeName(), c.getTypeName()); 103 assertEquals(val.getTypeName(), c.getTypeName() + "/val"); 104 assertEquals(box, c); 105 assertEquals(val.asBoxType(), box); 106 assertEquals(box.asValueType(), val); 107 } 108 109 void testArrayOfQType() { 110 Class<?> elementType = c.asValueType(); 111 Object array = Array.newInstance(elementType, 1); 112 Class<?> arrayType = array.getClass(); 113 assertTrue(arrayType.isArray()); 114 Class<?> componentType = arrayType.getComponentType(); 115 assertTrue(componentType.isValue()); 116 assertEquals(componentType, elementType); 117 // Array is a reference type 118 assertEquals(arrayType.asBoxType(), arrayType); 119 } 120 121 void accessFieldX(int x) throws Exception { 122 Field field = c.getField("x"); 123 if (field.getInt(o) != x) { 124 throw new RuntimeException("Unexpected Point.x value: " + field.getInt(o)); 125 } 126 127 try { 128 field.setInt(o, 100); 129 throw new RuntimeException("IllegalAccessException not thrown"); 130 } catch (IllegalAccessException e) {} 131 } 132 133 void newInstance() throws Exception { 134 try { 135 Object o = c.newInstance(); 136 throw new RuntimeException("newInstance expected to be unsupported on inline class"); 137 } catch (IllegalAccessException e) {} 138 } 139 140 void constructor() throws Exception { 141 try { 142 ctor.newInstance(); 143 throw new RuntimeException("IllegalAccessException not thrown"); 144 } catch (IllegalAccessException e) { } 145 } 146 147 void setAccessible() throws Exception { 148 try { 149 ctor.setAccessible(true); 150 throw new RuntimeException("InaccessibleObjectException not thrown"); 151 } catch (InaccessibleObjectException e) { e.printStackTrace(); } 152 Field field = c.getField("x"); 153 try { 154 field.setAccessible(true); 155 throw new RuntimeException("InaccessibleObjectException not thrown"); 156 } catch (InaccessibleObjectException e) { e.printStackTrace(); } 157 } 158 159 void trySetAccessible() throws Exception { 160 if (ctor.trySetAccessible()) { 161 throw new RuntimeException("trySetAccessible should not succeed"); 162 } 163 Field field = c.getField("x"); 164 if (field.trySetAccessible()) { 165 throw new RuntimeException("trySetAccessible should not succeed"); 166 } 167 } 168 169 void staticField() throws Exception { 170 Field f = c.getDeclaredField("STATIC_FIELD"); 171 if (f.trySetAccessible()) { 172 throw new RuntimeException("trySetAccessible should not succeed"); 173 } 174 try { 175 f.setAccessible(true); 176 throw new RuntimeException("IllegalAccessException not thrown"); 177 } catch (InaccessibleObjectException e) { } 178 } 179 180 void checkField(String name, Class<?> type) throws Exception { 181 Field f = c.getDeclaredField(name); 182 System.out.format("Field %s::%s of type %s = %s%n", 183 f.getDeclaringClass().getTypeName(), f.getName(), 184 f.getType().getTypeName(), f.get(o)); 185 assertEquals(f.getType(), type); 186 } 187 188 void checkMethod(String name, Class<?> returnType, Class<?>... params) throws Exception { 189 Method m = c.getDeclaredMethod(name, params); 190 191 String paramDesc = (params == null || params.length == 0) ? "" : 192 Arrays.stream(params).map(Class::getTypeName).collect(Collectors.joining(", ")); 193 System.out.format("Method %s::%s(%s)%s%n", 194 m.getDeclaringClass().getTypeName(), m.getName(), 195 paramDesc, returnType.getTypeName()); 196 } 197 198 static void assertEquals(Object o1, Object o2) { 199 if (o1 == o2 || o1.equals(o2)) 200 return; 201 202 throw new AssertionError(o1 + " != " + o2); 203 } 204 205 static void assertTrue(boolean value) { 206 if (!value) 207 throw new AssertionError("expected true"); 208 209 } 210 }