1 /* 2 * Copyright (c) 2014, 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 package java.lang.invoke; 25 26 import sun.invoke.util.Wrapper; 27 28 /* @test 29 * @summary unit tests for MethodHandles.explicitCastArguments() 30 * 31 * @run main/bootclasspath java.lang.invoke.ExplicitCastArgumentsTest 32 */ 33 public class ExplicitCastArgumentsTest { 34 private static final boolean VERBOSE = Boolean.getBoolean("verbose"); 35 private static final Class<?> THIS_CLASS = ExplicitCastArgumentsTest.class; 36 37 public static void main(String[] args) throws Throwable { 38 testVarargsCollector(); 39 testRef2Prim(); 40 System.out.println("TEST PASSED"); 41 } 42 43 public static String[] f(String... args) { return args; } 44 45 public static void testVarargsCollector() throws Throwable { 46 MethodType mt = MethodType.methodType(String[].class, String[].class); 47 MethodHandle mh = MethodHandles.publicLookup().findStatic(THIS_CLASS, "f", mt); 48 mh = MethodHandles.explicitCastArguments(mh, MethodType.methodType(Object.class, Object.class)); 49 mh.invokeWithArguments((Object)(new String[] {"str1", "str2"})); 50 } 51 52 public static void testRef2Prim() throws Throwable { 53 for (Wrapper from : Wrapper.values()) { 54 for (Wrapper to : Wrapper.values()) { 55 if (from == Wrapper.VOID || to == Wrapper.VOID) continue; 56 testRef2Prim(from, to); 57 } 58 } 59 } 60 61 public static void testRef2Prim(Wrapper from, Wrapper to) throws Throwable { 62 // MHs.eCA javadoc: 63 // If T0 is a reference and T1 a primitive, and if the reference is null at runtime, a zero value is introduced. 64 test(from.wrapperType(), to.primitiveType(), null, false); 65 } 66 67 public static void test(Class<?> from, Class<?> to, Object param, boolean failureExpected) throws Throwable { 68 if (VERBOSE) System.out.printf("%-10s => %-10s: %5s: ", from.getSimpleName(), to.getSimpleName(), param); 69 70 MethodHandle original = MethodHandles.identity(from); 71 MethodType newType = original.type().changeReturnType(to); 72 73 try { 74 MethodHandle target = MethodHandles.explicitCastArguments(original, newType); 75 Object result = target.invokeWithArguments(param); 76 77 if (VERBOSE) { 78 String resultStr; 79 if (result != null) { 80 resultStr = String.format("%10s (%10s)", "'"+result+"'", result.getClass().getSimpleName()); 81 } else { 82 resultStr = String.format("%10s", result); 83 } 84 System.out.println(resultStr); 85 } 86 87 if (failureExpected) { 88 String msg = String.format("No exception thrown: %s => %s; parameter: %s", from, to, param); 89 throw new AssertionError(msg); 90 } 91 } catch (AssertionError e) { 92 throw e; // report test failure 93 } catch (Throwable e) { 94 if (VERBOSE) System.out.printf("%s: %s\n", e.getClass(), e.getMessage()); 95 if (!failureExpected) { 96 String msg = String.format("Unexpected exception was thrown: %s => %s; parameter: %s", from, to, param); 97 throw new AssertionError(msg, e); 98 } 99 } 100 } 101 } | 1 /* 2 * Copyright (c) 2014, 2015, 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 import com.oracle.testlibrary.jsr292.Helper; 25 import java.io.File; 26 import java.io.Serializable; 27 import java.lang.invoke.MethodHandle; 28 import java.lang.invoke.MethodHandles; 29 import java.lang.invoke.MethodType; 30 import java.lang.invoke.WrongMethodTypeException; 31 import java.util.HashMap; 32 import java.util.Map; 33 import java.util.Random; 34 import sun.invoke.util.Wrapper; 35 36 /* 37 * @test 38 * @bug 8060483 8066746 39 * @key randomness 40 * @library /lib/testlibrary /lib/testlibrary/jsr292 41 * @summary unit tests for MethodHandles.explicitCastArguments() 42 * @run main ExplicitCastArgumentsTest 43 */ 44 45 /** 46 * Tests for MethodHandles.explicitCastArguments(). 47 */ 48 public class ExplicitCastArgumentsTest { 49 50 private static final boolean VERBOSE = Helper.IS_VERBOSE; 51 private static final Class<?> THIS_CLASS = ExplicitCastArgumentsTest.class; 52 private static final Random RNG = Helper.RNG; 53 private static final Map<Wrapper, Object> RANDOM_VALUES = new HashMap<>(9); 54 55 static { 56 RANDOM_VALUES.put(Wrapper.BOOLEAN, RNG.nextBoolean()); 57 RANDOM_VALUES.put(Wrapper.BYTE, (byte) RNG.nextInt()); 58 RANDOM_VALUES.put(Wrapper.SHORT, (short) RNG.nextInt()); 59 RANDOM_VALUES.put(Wrapper.CHAR, (char) RNG.nextInt()); 60 RANDOM_VALUES.put(Wrapper.INT, RNG.nextInt()); 61 RANDOM_VALUES.put(Wrapper.LONG, RNG.nextLong()); 62 RANDOM_VALUES.put(Wrapper.FLOAT, RNG.nextFloat()); 63 RANDOM_VALUES.put(Wrapper.DOUBLE, RNG.nextDouble()); 64 RANDOM_VALUES.put(Wrapper.OBJECT, new Object()); 65 } 66 67 public static void main(String[] args) throws Throwable { 68 testVarargsCollector(); 69 testNullRef2Prim(); 70 testRef2Prim(); 71 testPrim2Ref(); 72 testPrim2Prim(); 73 testNonBCPRef2NonBCPRef(); 74 testBCPRef2BCPRef(); 75 testNonBCPRef2BCPRef(); 76 testReturnAny2Void(); 77 testReturnVoid2Any(); 78 testMultipleArgs(); 79 System.out.println("TEST PASSED"); 80 } 81 82 /** 83 * Dummy method used in {@link #testVarargsCollector} test to form a method 84 * handle. 85 * 86 * @param args - any args 87 * @return - returns args 88 */ 89 public static String[] f(String... args) { 90 return args; 91 } 92 93 /** 94 * Tests that MHs.explicitCastArguments does incorrect type checks for 95 * VarargsCollector. Bug 8066746. 96 * 97 * @throws java.lang.Throwable 98 */ 99 public static void testVarargsCollector() throws Throwable { 100 MethodType mt = MethodType.methodType(String[].class, String[].class); 101 MethodHandle mh = MethodHandles.publicLookup() 102 .findStatic(THIS_CLASS, "f", mt); 103 mh = MethodHandles.explicitCastArguments(mh, 104 MethodType.methodType(Object.class, Object.class)); 105 mh.invokeWithArguments((Object) (new String[]{"str1", "str2"})); 106 } 107 108 /** 109 * Tests that null wrapper reference is successfully converted to primitive 110 * types. Converted result should be zero for a primitive. Bug 8060483. 111 */ 112 public static void testNullRef2Prim() { 113 for (Wrapper from : Wrapper.values()) { 114 for (Wrapper to : Wrapper.values()) { 115 if (from == Wrapper.VOID || to == Wrapper.VOID) { 116 continue; 117 } 118 // MHs.eCA javadoc: 119 // If T0 is a reference and T1 a primitive, and if the reference 120 // is null at runtime, a zero value is introduced. 121 for (TestConversionMode mode : TestConversionMode.values()) { 122 testConversion(mode, from.wrapperType(), 123 to.primitiveType(), null, to.zero(), false, null); 124 } 125 } 126 } 127 } 128 129 /** 130 * Tests that non-null wrapper reference is successfully converted to 131 * primitive types. 132 */ 133 public static void testRef2Prim() { 134 for (Wrapper from : Wrapper.values()) { 135 for (Wrapper to : Wrapper.values()) { 136 if (from == Wrapper.VOID || to == Wrapper.VOID 137 || to == Wrapper.OBJECT) { 138 continue; 139 } 140 Object value = RANDOM_VALUES.get(from); 141 for (TestConversionMode mode : TestConversionMode.values()) { 142 if (from != Wrapper.OBJECT) { 143 Object convValue = to.wrap(value); 144 testConversion(mode, from.wrapperType(), 145 to.primitiveType(), value, convValue, false, null); 146 } else { 147 testConversion(mode, from.wrapperType(), 148 to.primitiveType(), value, null, 149 true, ClassCastException.class); 150 } 151 } 152 } 153 } 154 } 155 156 /** 157 * Tests that primitive is successfully converted to wrapper reference 158 * types, to the Number type (if possible) and to the Object type. 159 */ 160 public static void testPrim2Ref() { 161 for (Wrapper from : Wrapper.values()) { 162 for (Wrapper to : Wrapper.values()) { 163 if (from == Wrapper.VOID || from == Wrapper.OBJECT 164 || to == Wrapper.VOID || to == Wrapper.OBJECT) { 165 continue; 166 } 167 Object value = RANDOM_VALUES.get(from); 168 for (TestConversionMode mode : TestConversionMode.values()) { 169 if (from == to) { 170 testConversion(mode, from.primitiveType(), 171 to.wrapperType(), value, value, false, null); 172 } else { 173 testConversion(mode, from.primitiveType(), 174 to.wrapperType(), value, null, true, ClassCastException.class); 175 } 176 if (from != Wrapper.BOOLEAN && from != Wrapper.CHAR) { 177 testConversion(mode, from.primitiveType(), 178 Number.class, value, value, false, null); 179 } else { 180 testConversion(mode, from.primitiveType(), 181 Number.class, value, null, 182 true, ClassCastException.class); 183 } 184 testConversion(mode, from.primitiveType(), 185 Object.class, value, value, false, null); 186 } 187 } 188 } 189 } 190 191 /** 192 * Tests that primitive is successfully converted to other primitive type. 193 */ 194 public static void testPrim2Prim() { 195 for (Wrapper from : Wrapper.values()) { 196 for (Wrapper to : Wrapper.values()) { 197 if (from == Wrapper.VOID || to == Wrapper.VOID 198 || from == Wrapper.OBJECT || to == Wrapper.OBJECT) { 199 continue; 200 } 201 Object value = RANDOM_VALUES.get(from); 202 Object convValue = to.wrap(value); 203 for (TestConversionMode mode : TestConversionMode.values()) { 204 testConversion(mode, from.primitiveType(), 205 to.primitiveType(), value, convValue, false, null); 206 } 207 } 208 } 209 } 210 211 /** 212 * Dummy interface for {@link #testNonBCPRef2Ref} test. 213 */ 214 public static interface TestInterface {} 215 216 /** 217 * Dummy class for {@link #testNonBCPRef2Ref} test. 218 */ 219 public static class TestSuperClass implements TestInterface {} 220 221 /** 222 * Dummy class for {@link #testNonBCPRef2Ref} test. 223 */ 224 public static class TestSubClass1 extends TestSuperClass {} 225 226 /** 227 * Dummy class for {@link #testNonBCPRef2Ref} test. 228 */ 229 public static class TestSubClass2 extends TestSuperClass {} 230 231 /** 232 * Tests non-bootclasspath reference to reference conversions. 233 * 234 * @throws java.lang.Throwable 235 */ 236 public static void testNonBCPRef2NonBCPRef() throws Throwable { 237 Class testInterface = TestInterface.class; 238 Class testSuperClass = TestSuperClass.class; 239 Class testSubClass1 = TestSubClass1.class; 240 Class testSubClass2 = TestSubClass2.class; 241 Object testSuperObj = new TestSuperClass(); 242 Object testObj01 = new TestSubClass1(); 243 Object testObj02 = new TestSubClass2(); 244 Class[] parents = {testInterface, testSuperClass}; 245 Class[] children = {testSubClass1, testSubClass2}; 246 Object[] childInst = {testObj01, testObj02}; 247 for (TestConversionMode mode : TestConversionMode.values()) { 248 for (Class parent : parents) { 249 for (int j = 0; j < children.length; j++) { 250 // Child type to parent type non-null conversion, shoud succeed 251 testConversion(mode, children[j], parent, childInst[j], childInst[j], false, null); 252 // Child type to parent type null conversion, shoud succeed 253 testConversion(mode, children[j], parent, null, null, false, null); 254 // Parent type to child type non-null conversion with parent 255 // type instance, should fail 256 testConversion(mode, parent, children[j], testSuperObj, null, true, ClassCastException.class); 257 // Parent type to child type non-null conversion with child 258 // type instance, should succeed 259 testConversion(mode, parent, children[j], childInst[j], childInst[j], false, null); 260 // Parent type to child type null conversion, should succeed 261 testConversion(mode, parent, children[j], null, null, false, null); 262 } 263 // Parent type to child type non-null conversion with sibling 264 // type instance, should fail 265 testConversion(mode, parent, testSubClass1, testObj02, null, true, ClassCastException.class); 266 } 267 // Sibling type non-null conversion, should fail 268 testConversion(mode, testSubClass1, 269 testSubClass2, testObj01, null, true, 270 ClassCastException.class); 271 // Sibling type null conversion, should succeed 272 testConversion(mode, testSubClass1, 273 testSubClass2, null, null, false, null); 274 } 275 } 276 277 /** 278 * Dummy interface for {@link #testNonBCPRef2BCPRef} test. 279 */ 280 public static interface TestSerializableInterface extends Serializable {} 281 282 /** 283 * Dummy class for {@link #testNonBCPRef2BCPRef} test. 284 */ 285 public static class TestSerializableClass 286 implements TestSerializableInterface {} 287 288 /** 289 * Dummy class for {@link #testNonBCPRef2BCPRef} test. 290 */ 291 public static class TestFileChildClass extends File 292 implements TestSerializableInterface { 293 public TestFileChildClass(String pathname) { 294 super(pathname); 295 } 296 } 297 298 /** 299 * Tests non-bootclasspath reference to bootclasspath reference conversions 300 * and vice-versa. 301 * 302 * @throws java.lang.Throwable 303 */ 304 public static void testNonBCPRef2BCPRef() throws Throwable { 305 Class bcpInterface = Serializable.class; 306 Class bcpSuperClass = File.class; 307 Class nonBcpInterface = TestSerializableInterface.class; 308 Class nonBcpSuperSiblingClass = TestSerializableClass.class; 309 Class nonBcpSubClass = TestFileChildClass.class; 310 Object bcpSuperObj = new File("."); 311 Object testSuperSiblingObj = new TestSerializableClass(); 312 Object testSubObj = new TestFileChildClass("."); 313 Class[] parents = {bcpInterface, bcpSuperClass}; 314 for (TestConversionMode mode : TestConversionMode.values()) { 315 for (Class parent : parents) { 316 // Child type to parent type non-null conversion, shoud succeed 317 testConversion(mode, nonBcpSubClass, parent, testSubObj, 318 testSubObj, false, null); 319 // Child type to parent type null conversion, shoud succeed 320 testConversion(mode, nonBcpSubClass, parent, null, null, 321 false, null); 322 // Parent type to child type non-null conversion with parent 323 // type instance, should fail 324 testConversion(mode, parent, nonBcpSubClass, bcpSuperObj, null, 325 true, ClassCastException.class); 326 // Parent type to child type non-null conversion with child 327 // type instance, should succeed 328 testConversion(mode, parent, nonBcpSubClass, testSubObj, 329 testSubObj, false, null); 330 // Parent type to child type null conversion, should succeed 331 testConversion(mode, parent, nonBcpSubClass, null, null, 332 false, null); 333 } 334 // Parent type to child type non-null conversion with 335 // super sibling type instance, should fail 336 testConversion(mode, bcpInterface, nonBcpSubClass, 337 testSuperSiblingObj, null, true, ClassCastException.class); 338 Class[] siblings = {nonBcpSubClass, bcpSuperClass}; 339 for (Class sibling : siblings) { 340 // Non-bcp class to bcp/non-bcp sibling class non-null 341 // conversion with nonBcpSuperSiblingClass instance, should fail 342 testConversion(mode, nonBcpSuperSiblingClass, sibling, 343 testSuperSiblingObj, null, true, ClassCastException.class); 344 // Non-bcp class to bcp/non-bcp sibling class null conversion, 345 // should succeed 346 testConversion(mode, nonBcpSuperSiblingClass, sibling, 347 null, null, false, null); 348 // Non-bcp interface to bcp/non-bcp sibling class non-null 349 // conversion with nonBcpSubClass instance, should succeed 350 testConversion(mode, nonBcpInterface, sibling, testSubObj, 351 testSubObj, false, null); 352 // Non-bcp interface to bcp/non-bcp sibling class 353 // null conversion, should succeed 354 testConversion(mode, nonBcpInterface, sibling, null, null, 355 false, null); 356 // Non-bcp interface to bcp/non-bcp sibling class non-null 357 // conversion with nonBcpSuperSiblingClass instance, should fail 358 testConversion(mode, nonBcpInterface, sibling, 359 testSuperSiblingObj, testSubObj, 360 true, ClassCastException.class); 361 } 362 } 363 } 364 365 /** 366 * Tests bootclasspath reference to reference conversions. 367 */ 368 public static void testBCPRef2BCPRef() { 369 Class bcpInterface = CharSequence.class; 370 Class bcpSubClass1 = String.class; 371 Class bcpSubClass2 = StringBuffer.class; 372 Object testObj01 = new String("test"); 373 Object testObj02 = new StringBuffer("test"); 374 Class[] children = {bcpSubClass1, bcpSubClass2}; 375 Object[] childInst = {testObj01, testObj02}; 376 for (TestConversionMode mode : TestConversionMode.values()) { 377 for (int i = 0; i < children.length; i++) { 378 // Child type to parent type non-null conversion, shoud succeed 379 testConversion(mode, children[i], bcpInterface, childInst[i], 380 childInst[i], false, null); 381 // Child type to parent type null conversion, shoud succeed 382 testConversion(mode, children[i], bcpInterface, null, 383 null, false, null); 384 // Parent type to child type non-null conversion with child 385 // type instance, should succeed 386 testConversion(mode, bcpInterface, 387 children[i], childInst[i], childInst[i], false, null); 388 // Parent type to child type null conversion, should succeed 389 testConversion(mode, bcpInterface, 390 children[i], null, null, false, null); 391 } 392 // Sibling type non-null conversion, should fail 393 testConversion(mode, bcpSubClass1, 394 bcpSubClass2, testObj01, null, true, 395 ClassCastException.class); 396 // Sibling type null conversion, should succeed 397 testConversion(mode, bcpSubClass1, 398 bcpSubClass2, null, null, false, null); 399 // Parent type to child type non-null conversion with sibling 400 // type instance, should fail 401 testConversion(mode, bcpInterface, bcpSubClass1, testObj02, 402 null, true, ClassCastException.class); 403 } 404 } 405 406 /** 407 * Dummy method used in {@link #testReturnAny2Void} and 408 * {@link #testReturnVoid2Any} tests to form a method handle. 409 */ 410 public static void retVoid() {} 411 412 /** 413 * Tests that non-null any return is successfully converted to non-type 414 * void. 415 */ 416 public static void testReturnAny2Void() { 417 for (Wrapper from : Wrapper.values()) { 418 testConversion(TestConversionMode.RETURN_VALUE, from.wrapperType(), 419 void.class, RANDOM_VALUES.get(from), 420 null, false, null); 421 testConversion(TestConversionMode.RETURN_VALUE, from.primitiveType(), 422 void.class, RANDOM_VALUES.get(from), 423 null, false, null); 424 } 425 } 426 427 /** 428 * Tests that void return is successfully converted to primitive and 429 * reference. Result should be zero for primitives and null for references. 430 */ 431 public static void testReturnVoid2Any() { 432 for (Wrapper to : Wrapper.values()) { 433 testConversion(TestConversionMode.RETURN_VALUE, void.class, 434 to.primitiveType(), null, 435 to.zero(), false, null); 436 testConversion(TestConversionMode.RETURN_VALUE, void.class, 437 to.wrapperType(), null, 438 null, false, null); 439 } 440 } 441 442 private static void checkForWrongMethodTypeException(MethodHandle mh, MethodType mt) { 443 try { 444 MethodHandles.explicitCastArguments(mh, mt); 445 throw new AssertionError("Expected WrongMethodTypeException is not thrown"); 446 } catch (WrongMethodTypeException wmte) { 447 if (VERBOSE) { 448 System.out.printf("Expected exception %s: %s\n", 449 wmte.getClass(), wmte.getMessage()); 450 } 451 } 452 } 453 454 /** 455 * Tests that MHs.eCA method works correctly with MHs with multiple arguments. 456 * @throws Throwable 457 */ 458 public static void testMultipleArgs() throws Throwable { 459 int arity = 1 + RNG.nextInt(Helper.MAX_ARITY / 2 - 2); 460 int arityMinus = RNG.nextInt(arity); 461 int arityPlus = arity + RNG.nextInt(Helper.MAX_ARITY / 2 - arity) + 1; 462 MethodType mType = Helper.randomMethodTypeGenerator(arity); 463 MethodType mTypeNew = Helper.randomMethodTypeGenerator(arity); 464 MethodType mTypeNewMinus = Helper.randomMethodTypeGenerator(arityMinus); 465 MethodType mTypeNewPlus = Helper.randomMethodTypeGenerator(arityPlus); 466 Class<?> rType = mType.returnType(); 467 MethodHandle original; 468 if (rType.equals(void.class)) { 469 MethodType mt = MethodType.methodType(void.class); 470 original = MethodHandles.publicLookup() 471 .findStatic(THIS_CLASS, "retVoid", mt); 472 } else { 473 Object rValue = Helper.castToWrapper(1, rType); 474 original = MethodHandles.constant(rType, rValue); 475 } 476 original = Helper.addTrailingArgs(original, arity, mType.parameterList()); 477 MethodHandle target = MethodHandles 478 .explicitCastArguments(original, mTypeNew); 479 Object[] parList = Helper.randomArgs(mTypeNew.parameterList()); 480 for (int i = 0; i < parList.length; i++) { 481 if (parList[i] instanceof String) { 482 parList[i] = null; //getting rid of Stings produced by randomArgs 483 } 484 } 485 target.invokeWithArguments(parList); 486 checkForWrongMethodTypeException(original, mTypeNewMinus); 487 checkForWrongMethodTypeException(original, mTypeNewPlus); 488 } 489 490 /** 491 * Enumeration of test conversion modes. 492 */ 493 public enum TestConversionMode { 494 RETURN_VALUE, 495 ARGUMENT; 496 } 497 498 /** 499 * Tests type and value conversion. Comparing with the given expected result. 500 * 501 * @param mode - test conversion mode. See {@link #TestConversionMode}. 502 * @param from - source type. 503 * @param to - destination type. 504 * @param param - value to be converted. 505 * @param expectedResult - expected value after conversion. 506 * @param failureExpected - true if conversion failure expected. 507 * @param expectedException - expected exception class if 508 * {@code failureExpected} is true. 509 */ 510 public static void testConversion(TestConversionMode mode, 511 Class<?> from, Class<?> to, Object param, 512 Object expectedResult, boolean failureExpected, 513 Class<? extends Throwable> expectedException) { 514 if (VERBOSE) { 515 System.out.printf("Testing return value conversion: " 516 + "%-10s => %-10s: %5s: ", from.getSimpleName(), 517 to.getSimpleName(), param); 518 } 519 MethodHandle original = null; 520 MethodType newType = null; 521 switch (mode) { 522 case RETURN_VALUE: 523 if (from.equals(void.class)) { 524 MethodType mt = MethodType.methodType(void.class); 525 try { 526 original = MethodHandles.publicLookup() 527 .findStatic(THIS_CLASS, "retVoid", mt); 528 } catch (NoSuchMethodException | IllegalAccessException ex) { 529 throw new Error("Unexpected issue", ex); 530 } 531 } else { 532 original = MethodHandles.constant(from, param); 533 } 534 newType = original.type().changeReturnType(to); 535 break; 536 case ARGUMENT: 537 if (from.equals(void.class) || to.equals(void.class)) { 538 throw new Error("Test issue: argument conversion does not" 539 + " work with non-type void"); 540 } 541 original = MethodHandles.identity(to); 542 newType = original.type().changeParameterType(0, from); 543 break; 544 default: 545 String msg = String.format("Test issue: unknown test" 546 + " convertion mode %s.", mode.name()); 547 throw new Error(msg); 548 } 549 try { 550 MethodHandle target = MethodHandles 551 .explicitCastArguments(original, newType); 552 Object result; 553 switch (mode) { 554 case RETURN_VALUE: 555 result = target.invokeWithArguments(); 556 break; 557 case ARGUMENT: 558 result = target.invokeWithArguments(param); 559 break; 560 default: 561 String msg = String.format("Test issue: unknown test" 562 + " convertion mode %s.", mode.name()); 563 throw new Error(msg); 564 } 565 if (!failureExpected 566 && (expectedResult != null && !expectedResult.equals(result) 567 || expectedResult == null && result != null)) { 568 String msg = String.format("Conversion result %s is not equal" 569 + " to the expected result %10s", 570 result, expectedResult); 571 throw new AssertionError(msg); 572 } 573 if (VERBOSE) { 574 String resultStr; 575 if (result != null) { 576 resultStr = String.format("Converted value and type are" 577 + " %10s (%10s)", "'" + result + "'", 578 result.getClass().getSimpleName()); 579 } else { 580 resultStr = String.format("Converted value is %10s", result); 581 } 582 System.out.println(resultStr); 583 } 584 if (failureExpected) { 585 String msg = String.format("No exception thrown while testing" 586 + " return value conversion: %10s => %10s;" 587 + " parameter: %10s", 588 from, to, param); 589 throw new AssertionError(msg); 590 } 591 } catch (AssertionError e) { 592 throw e; // report test failure 593 } catch (Throwable e) { 594 if (VERBOSE) { 595 System.out.printf("%s: %s\n", e.getClass(), e.getMessage()); 596 } 597 if (!failureExpected || !e.getClass().equals(expectedException)) { 598 String msg = String.format("Unexpected exception was thrown" 599 + " while testing return value conversion:" 600 + " %s => %s; parameter: %s", from, to, param); 601 throw new AssertionError(msg, e); 602 } 603 } 604 } 605 } |