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