1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import java.lang.invoke.MethodHandle; 18 import java.lang.invoke.MethodHandles; 19 import java.lang.invoke.MethodHandles.Lookup; 20 import java.lang.invoke.MethodType; 21 import java.lang.invoke.WrongMethodTypeException; 22 23 public class Main { 24 public static void main(String[] args) throws Throwable { 25 testThrowException(); 26 testDropArguments(); 27 testCatchException(); 28 testGuardWithTest(); 29 testArrayElementGetter(); 30 testArrayElementSetter(); 31 testIdentity(); 32 testConstant(); 33 testBindTo(); 34 testFilterReturnValue(); 35 testPermuteArguments(); 36 testInvokers(); 37 testSpreaders_reference(); 38 testSpreaders_primitive(); 39 testInvokeWithArguments(); 40 testAsCollector(); 41 testFilterArguments(); 42 testCollectArguments(); 43 testInsertArguments(); 44 testFoldArguments(); 45 } 46 47 public static void testThrowException() throws Throwable { 48 MethodHandle handle = MethodHandles.throwException(String.class, 49 IllegalArgumentException.class); 50 51 if (handle.type().returnType() != String.class) { 52 fail("Unexpected return type for handle: " + handle + 53 " [ " + handle.type() + "]"); 54 } 55 56 final IllegalArgumentException iae = new IllegalArgumentException("boo!"); 57 try { 58 handle.invoke(iae); 59 fail("Expected an exception of type: java.lang.IllegalArgumentException"); 60 } catch (IllegalArgumentException expected) { 61 if (expected != iae) { 62 fail("Wrong exception: expected " + iae + " but was " + expected); 63 } 64 } 65 } 66 67 public static void dropArguments_delegate(String message, long message2) { 68 System.out.println("Message: " + message + ", Message2: " + message2); 69 } 70 71 public static void testDropArguments() throws Throwable { 72 MethodHandle delegate = MethodHandles.lookup().findStatic(Main.class, 73 "dropArguments_delegate", 74 MethodType.methodType(void.class, new Class<?>[] { String.class, long.class })); 75 76 MethodHandle transform = MethodHandles.dropArguments(delegate, 0, int.class, Object.class); 77 78 // The transformer will accept two additional arguments at position zero. 79 try { 80 transform.invokeExact("foo", 42l); 81 fail(); 82 } catch (WrongMethodTypeException expected) { 83 } 84 85 transform.invokeExact(45, new Object(), "foo", 42l); 86 transform.invoke(45, new Object(), "foo", 42l); 87 88 // Additional arguments at position 1. 89 transform = MethodHandles.dropArguments(delegate, 1, int.class, Object.class); 90 transform.invokeExact("foo", 45, new Object(), 42l); 91 transform.invoke("foo", 45, new Object(), 42l); 92 93 // Additional arguments at position 2. 94 transform = MethodHandles.dropArguments(delegate, 2, int.class, Object.class); 95 transform.invokeExact("foo", 42l, 45, new Object()); 96 transform.invoke("foo", 42l, 45, new Object()); 97 98 // Note that we still perform argument conversions even for the arguments that 99 // are subsequently dropped. 100 try { 101 transform.invoke("foo", 42l, 45l, new Object()); 102 fail(); 103 } catch (WrongMethodTypeException expected) { 104 } catch (IllegalArgumentException expected) { 105 // TODO(narayan): We currently throw the wrong type of exception here, 106 // it's IAE and should be WMTE instead. 107 } 108 109 // Check that asType works as expected. 110 transform = MethodHandles.dropArguments(delegate, 0, int.class, Object.class); 111 transform = transform.asType(MethodType.methodType(void.class, 112 new Class<?>[] { short.class, Object.class, String.class, long.class })); 113 transform.invokeExact((short) 45, new Object(), "foo", 42l); 114 115 // Invalid argument location, should not be allowed. 116 try { 117 MethodHandles.dropArguments(delegate, -1, int.class, Object.class); 118 fail(); 119 } catch (IllegalArgumentException expected) { 120 } 121 122 // Invalid argument location, should not be allowed. 123 try { 124 MethodHandles.dropArguments(delegate, 3, int.class, Object.class); 125 fail(); 126 } catch (IllegalArgumentException expected) { 127 } 128 129 try { 130 MethodHandles.dropArguments(delegate, 1, void.class); 131 fail(); 132 } catch (IllegalArgumentException expected) { 133 } 134 } 135 136 public static String testCatchException_target(String arg1, long arg2, String exceptionMessage) 137 throws Throwable { 138 if (exceptionMessage != null) { 139 throw new IllegalArgumentException(exceptionMessage); 140 } 141 142 System.out.println("Target: Arg1: " + arg1 + ", Arg2: " + arg2); 143 return "target"; 144 } 145 146 public static String testCatchException_handler(IllegalArgumentException iae, String arg1, long arg2, 147 String exMsg) { 148 System.out.println("Handler: " + iae + ", Arg1: " + arg1 + ", Arg2: " + arg2 + ", ExMsg: " + exMsg); 149 return "handler1"; 150 } 151 152 public static String testCatchException_handler2(IllegalArgumentException iae, String arg1) { 153 System.out.println("Handler: " + iae + ", Arg1: " + arg1); 154 return "handler2"; 155 } 156 157 public static void testCatchException() throws Throwable { 158 MethodHandle target = MethodHandles.lookup().findStatic(Main.class, 159 "testCatchException_target", 160 MethodType.methodType(String.class, new Class<?>[] { String.class, long.class, String.class })); 161 162 MethodHandle handler = MethodHandles.lookup().findStatic(Main.class, 163 "testCatchException_handler", 164 MethodType.methodType(String.class, new Class<?>[] { IllegalArgumentException.class, 165 String.class, long.class, String.class })); 166 167 MethodHandle adapter = MethodHandles.catchException(target, IllegalArgumentException.class, 168 handler); 169 170 String returnVal = null; 171 172 // These two should end up calling the target always. We're passing a null exception 173 // message here, which means the target will not throw. 174 returnVal = (String) adapter.invoke("foo", 42, null); 175 assertEquals("target", returnVal); 176 returnVal = (String) adapter.invokeExact("foo", 42l, (String) null); 177 assertEquals("target", returnVal); 178 179 // We're passing a non-null exception message here, which means the target will throw, 180 // which in turn means that the handler must be called for the next two invokes. 181 returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage"); 182 assertEquals("handler1", returnVal); 183 returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage"); 184 assertEquals("handler1", returnVal); 185 186 handler = MethodHandles.lookup().findStatic(Main.class, 187 "testCatchException_handler2", 188 MethodType.methodType(String.class, new Class<?>[] { IllegalArgumentException.class, 189 String.class })); 190 adapter = MethodHandles.catchException(target, IllegalArgumentException.class, handler); 191 192 returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage"); 193 assertEquals("handler2", returnVal); 194 returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage"); 195 assertEquals("handler2", returnVal); 196 197 // Test that the type of the invoke doesn't matter. Here we call 198 // IllegalArgumentException.toString() on the exception that was thrown by 199 // the target. 200 handler = MethodHandles.lookup().findVirtual(IllegalArgumentException.class, 201 "toString", MethodType.methodType(String.class)); 202 adapter = MethodHandles.catchException(target, IllegalArgumentException.class, handler); 203 204 returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage"); 205 assertEquals("java.lang.IllegalArgumentException: exceptionMessage", returnVal); 206 returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage2"); 207 assertEquals("java.lang.IllegalArgumentException: exceptionMessage2", returnVal); 208 209 // Check that asType works as expected. 210 adapter = MethodHandles.catchException(target, IllegalArgumentException.class, 211 handler); 212 adapter = adapter.asType(MethodType.methodType(String.class, 213 new Class<?>[] { String.class, int.class, String.class })); 214 returnVal = (String) adapter.invokeExact("foo", 42, "exceptionMessage"); 215 assertEquals("java.lang.IllegalArgumentException: exceptionMessage", returnVal); 216 } 217 218 public static boolean testGuardWithTest_test(String arg1, long arg2) { 219 return "target".equals(arg1) && 42 == arg2; 220 } 221 222 public static String testGuardWithTest_target(String arg1, long arg2, int arg3) { 223 System.out.println("target: " + arg1 + ", " + arg2 + ", " + arg3); 224 return "target"; 225 } 226 227 public static String testGuardWithTest_fallback(String arg1, long arg2, int arg3) { 228 System.out.println("fallback: " + arg1 + ", " + arg2 + ", " + arg3); 229 return "fallback"; 230 } 231 232 public static void testGuardWithTest() throws Throwable { 233 MethodHandle test = MethodHandles.lookup().findStatic(Main.class, 234 "testGuardWithTest_test", 235 MethodType.methodType(boolean.class, new Class<?>[] { String.class, long.class })); 236 237 final MethodType type = MethodType.methodType(String.class, 238 new Class<?>[] { String.class, long.class, int.class }); 239 240 final MethodHandle target = MethodHandles.lookup().findStatic(Main.class, 241 "testGuardWithTest_target", type); 242 final MethodHandle fallback = MethodHandles.lookup().findStatic(Main.class, 243 "testGuardWithTest_fallback", type); 244 245 MethodHandle adapter = MethodHandles.guardWithTest(test, target, fallback); 246 247 String returnVal = null; 248 249 returnVal = (String) adapter.invoke("target", 42, 56); 250 assertEquals("target", returnVal); 251 returnVal = (String) adapter.invokeExact("target", 42l, 56); 252 assertEquals("target", returnVal); 253 254 returnVal = (String) adapter.invoke("fallback", 42l, 56); 255 assertEquals("fallback", returnVal); 256 returnVal = (String) adapter.invokeExact("target", 42l, 56); 257 assertEquals("target", returnVal); 258 259 // Check that asType works as expected. 260 adapter = adapter.asType(MethodType.methodType(String.class, 261 new Class<?>[] { String.class, int.class, int.class })); 262 returnVal = (String) adapter.invokeExact("target", 42, 56); 263 assertEquals("target", returnVal); 264 } 265 266 public static void testArrayElementGetter() throws Throwable { 267 MethodHandle getter = MethodHandles.arrayElementGetter(int[].class); 268 269 { 270 int[] array = new int[1]; 271 array[0] = 42; 272 int value = (int) getter.invoke(array, 0); 273 if (value != 42) { 274 fail("Unexpected value: " + value); 275 } 276 277 try { 278 value = (int) getter.invoke(array, -1); 279 fail(); 280 } catch (ArrayIndexOutOfBoundsException expected) { 281 } 282 283 try { 284 value = (int) getter.invoke(null, -1); 285 fail(); 286 } catch (NullPointerException expected) { 287 } 288 } 289 290 { 291 getter = MethodHandles.arrayElementGetter(long[].class); 292 long[] array = new long[1]; 293 array[0] = 42; 294 long value = (long) getter.invoke(array, 0); 295 if (value != 42l) { 296 fail("Unexpected value: " + value); 297 } 298 } 299 300 { 301 getter = MethodHandles.arrayElementGetter(short[].class); 302 short[] array = new short[1]; 303 array[0] = 42; 304 short value = (short) getter.invoke(array, 0); 305 if (value != 42l) { 306 fail("Unexpected value: " + value); 307 } 308 } 309 310 { 311 getter = MethodHandles.arrayElementGetter(char[].class); 312 char[] array = new char[1]; 313 array[0] = 42; 314 char value = (char) getter.invoke(array, 0); 315 if (value != 42l) { 316 fail("Unexpected value: " + value); 317 } 318 } 319 320 { 321 getter = MethodHandles.arrayElementGetter(byte[].class); 322 byte[] array = new byte[1]; 323 array[0] = (byte) 0x8; 324 byte value = (byte) getter.invoke(array, 0); 325 if (value != (byte) 0x8) { 326 fail("Unexpected value: " + value); 327 } 328 } 329 330 { 331 getter = MethodHandles.arrayElementGetter(boolean[].class); 332 boolean[] array = new boolean[1]; 333 array[0] = true; 334 boolean value = (boolean) getter.invoke(array, 0); 335 if (!value) { 336 fail("Unexpected value: " + value); 337 } 338 } 339 340 { 341 getter = MethodHandles.arrayElementGetter(float[].class); 342 float[] array = new float[1]; 343 array[0] = 42.0f; 344 float value = (float) getter.invoke(array, 0); 345 if (value != 42.0f) { 346 fail("Unexpected value: " + value); 347 } 348 } 349 350 { 351 getter = MethodHandles.arrayElementGetter(double[].class); 352 double[] array = new double[1]; 353 array[0] = 42.0; 354 double value = (double) getter.invoke(array, 0); 355 if (value != 42.0) { 356 fail("Unexpected value: " + value); 357 } 358 } 359 360 { 361 getter = MethodHandles.arrayElementGetter(String[].class); 362 String[] array = new String[3]; 363 array[0] = "42"; 364 array[1] = "48"; 365 array[2] = "54"; 366 String value = (String) getter.invoke(array, 0); 367 assertEquals("42", value); 368 value = (String) getter.invoke(array, 1); 369 assertEquals("48", value); 370 value = (String) getter.invoke(array, 2); 371 assertEquals("54", value); 372 } 373 } 374 375 public static void testArrayElementSetter() throws Throwable { 376 MethodHandle setter = MethodHandles.arrayElementSetter(int[].class); 377 378 { 379 int[] array = new int[2]; 380 setter.invoke(array, 0, 42); 381 setter.invoke(array, 1, 43); 382 383 if (array[0] != 42) { 384 fail("Unexpected value: " + array[0]); 385 } 386 if (array[1] != 43) { 387 fail("Unexpected value: " + array[1]); 388 } 389 390 try { 391 setter.invoke(array, -1, 42); 392 fail(); 393 } catch (ArrayIndexOutOfBoundsException expected) { 394 } 395 396 try { 397 setter.invoke(null, 0, 42); 398 fail(); 399 } catch (NullPointerException expected) { 400 } 401 } 402 403 { 404 setter = MethodHandles.arrayElementSetter(long[].class); 405 long[] array = new long[1]; 406 setter.invoke(array, 0, 42l); 407 if (array[0] != 42l) { 408 fail("Unexpected value: " + array[0]); 409 } 410 } 411 412 { 413 setter = MethodHandles.arrayElementSetter(short[].class); 414 short[] array = new short[1]; 415 setter.invoke(array, 0, (short) 42); 416 if (array[0] != 42l) { 417 fail("Unexpected value: " + array[0]); 418 } 419 } 420 421 { 422 setter = MethodHandles.arrayElementSetter(char[].class); 423 char[] array = new char[1]; 424 setter.invoke(array, 0, (char) 42); 425 if (array[0] != 42) { 426 fail("Unexpected value: " + array[0]); 427 } 428 } 429 430 { 431 setter = MethodHandles.arrayElementSetter(byte[].class); 432 byte[] array = new byte[1]; 433 setter.invoke(array, 0, (byte) 0x8); 434 if (array[0] != (byte) 0x8) { 435 fail("Unexpected value: " + array[0]); 436 } 437 } 438 439 { 440 setter = MethodHandles.arrayElementSetter(boolean[].class); 441 boolean[] array = new boolean[1]; 442 setter.invoke(array, 0, true); 443 if (!array[0]) { 444 fail("Unexpected value: " + array[0]); 445 } 446 } 447 448 { 449 setter = MethodHandles.arrayElementSetter(float[].class); 450 float[] array = new float[1]; 451 setter.invoke(array, 0, 42.0f); 452 if (array[0] != 42.0f) { 453 fail("Unexpected value: " + array[0]); 454 } 455 } 456 457 { 458 setter = MethodHandles.arrayElementSetter(double[].class); 459 double[] array = new double[1]; 460 setter.invoke(array, 0, 42.0); 461 if (array[0] != 42.0) { 462 fail("Unexpected value: " + array[0]); 463 } 464 } 465 466 { 467 setter = MethodHandles.arrayElementSetter(String[].class); 468 String[] array = new String[3]; 469 setter.invoke(array, 0, "42"); 470 setter.invoke(array, 1, "48"); 471 setter.invoke(array, 2, "54"); 472 assertEquals("42", array[0]); 473 assertEquals("48", array[1]); 474 assertEquals("54", array[2]); 475 } 476 } 477 478 public static void testIdentity() throws Throwable { 479 { 480 MethodHandle identity = MethodHandles.identity(boolean.class); 481 boolean value = (boolean) identity.invoke(false); 482 if (value) { 483 fail("Unexpected value: " + value); 484 } 485 } 486 487 { 488 MethodHandle identity = MethodHandles.identity(byte.class); 489 byte value = (byte) identity.invoke((byte) 0x8); 490 if (value != (byte) 0x8) { 491 fail("Unexpected value: " + value); 492 } 493 } 494 495 { 496 MethodHandle identity = MethodHandles.identity(char.class); 497 char value = (char) identity.invoke((char) -56); 498 if (value != (char) -56) { 499 fail("Unexpected value: " + value); 500 } 501 } 502 503 { 504 MethodHandle identity = MethodHandles.identity(short.class); 505 short value = (short) identity.invoke((short) -59); 506 if (value != (short) -59) { 507 fail("Unexpected value: " + Short.toString(value)); 508 } 509 } 510 511 { 512 MethodHandle identity = MethodHandles.identity(int.class); 513 int value = (int) identity.invoke(52); 514 if (value != 52) { 515 fail("Unexpected value: " + value); 516 } 517 } 518 519 { 520 MethodHandle identity = MethodHandles.identity(long.class); 521 long value = (long) identity.invoke(-76l); 522 if (value != (long) -76) { 523 fail("Unexpected value: " + value); 524 } 525 } 526 527 { 528 MethodHandle identity = MethodHandles.identity(float.class); 529 float value = (float) identity.invoke(56.0f); 530 if (value != (float) 56.0f) { 531 fail("Unexpected value: " + value); 532 } 533 } 534 535 { 536 MethodHandle identity = MethodHandles.identity(double.class); 537 double value = (double) identity.invoke((double) 72.0); 538 if (value != (double) 72.0) { 539 fail("Unexpected value: " + value); 540 } 541 } 542 543 { 544 MethodHandle identity = MethodHandles.identity(String.class); 545 String value = (String) identity.invoke("bazman"); 546 assertEquals("bazman", value); 547 } 548 } 549 550 public static void testConstant() throws Throwable { 551 // int constants. 552 { 553 MethodHandle constant = MethodHandles.constant(int.class, 56); 554 int value = (int) constant.invoke(); 555 if (value != 56) { 556 fail("Unexpected value: " + value); 557 } 558 559 // short constant values are converted to int. 560 constant = MethodHandles.constant(int.class, (short) 52); 561 value = (int) constant.invoke(); 562 if (value != 52) { 563 fail("Unexpected value: " + value); 564 } 565 566 // char constant values are converted to int. 567 constant = MethodHandles.constant(int.class, (char) 'b'); 568 value = (int) constant.invoke(); 569 if (value != (int) 'b') { 570 fail("Unexpected value: " + value); 571 } 572 573 // int constant values are converted to int. 574 constant = MethodHandles.constant(int.class, (byte) 0x1); 575 value = (int) constant.invoke(); 576 if (value != 1) { 577 fail("Unexpected value: " + value); 578 } 579 580 // boolean, float, double and long primitive constants are not convertible 581 // to int, so the handle creation must fail with a CCE. 582 try { 583 MethodHandles.constant(int.class, false); 584 fail(); 585 } catch (ClassCastException expected) { 586 } 587 588 try { 589 MethodHandles.constant(int.class, 0.1f); 590 fail(); 591 } catch (ClassCastException expected) { 592 } 593 594 try { 595 MethodHandles.constant(int.class, 0.2); 596 fail(); 597 } catch (ClassCastException expected) { 598 } 599 600 try { 601 MethodHandles.constant(int.class, 73l); 602 fail(); 603 } catch (ClassCastException expected) { 604 } 605 } 606 607 // long constants. 608 { 609 MethodHandle constant = MethodHandles.constant(long.class, 56l); 610 long value = (long) constant.invoke(); 611 if (value != 56l) { 612 fail("Unexpected value: " + value); 613 } 614 615 constant = MethodHandles.constant(long.class, (int) 56); 616 value = (long) constant.invoke(); 617 if (value != 56l) { 618 fail("Unexpected value: " + value); 619 } 620 } 621 622 // byte constants. 623 { 624 MethodHandle constant = MethodHandles.constant(byte.class, (byte) 0x12); 625 byte value = (byte) constant.invoke(); 626 if (value != (byte) 0x12) { 627 fail("Unexpected value: " + value); 628 } 629 } 630 631 // boolean constants. 632 { 633 MethodHandle constant = MethodHandles.constant(boolean.class, true); 634 boolean value = (boolean) constant.invoke(); 635 if (!value) { 636 fail("Unexpected value: " + value); 637 } 638 } 639 640 // char constants. 641 { 642 MethodHandle constant = MethodHandles.constant(char.class, 'f'); 643 char value = (char) constant.invoke(); 644 if (value != 'f') { 645 fail("Unexpected value: " + value); 646 } 647 } 648 649 // short constants. 650 { 651 MethodHandle constant = MethodHandles.constant(short.class, (short) 123); 652 short value = (short) constant.invoke(); 653 if (value != (short) 123) { 654 fail("Unexpected value: " + value); 655 } 656 } 657 658 // float constants. 659 { 660 MethodHandle constant = MethodHandles.constant(float.class, 56.0f); 661 float value = (float) constant.invoke(); 662 if (value != 56.0f) { 663 fail("Unexpected value: " + value); 664 } 665 } 666 667 // double constants. 668 { 669 MethodHandle constant = MethodHandles.constant(double.class, 256.0); 670 double value = (double) constant.invoke(); 671 if (value != 256.0) { 672 fail("Unexpected value: " + value); 673 } 674 } 675 676 // reference constants. 677 { 678 MethodHandle constant = MethodHandles.constant(String.class, "256.0"); 679 String value = (String) constant.invoke(); 680 assertEquals("256.0", value); 681 } 682 } 683 684 public static void testBindTo() throws Throwable { 685 MethodHandle stringCharAt = MethodHandles.lookup().findVirtual( 686 String.class, "charAt", MethodType.methodType(char.class, int.class)); 687 688 char value = (char) stringCharAt.invoke("foo", 0); 689 if (value != 'f') { 690 fail("Unexpected value: " + value); 691 } 692 693 MethodHandle bound = stringCharAt.bindTo("foo"); 694 value = (char) bound.invoke(0); 695 if (value != 'f') { 696 fail("Unexpected value: " + value); 697 } 698 699 try { 700 stringCharAt.bindTo(new Object()); 701 fail(); 702 } catch (ClassCastException expected) { 703 } 704 705 bound = stringCharAt.bindTo(null); 706 try { 707 bound.invoke(0); 708 fail(); 709 } catch (NullPointerException expected) { 710 } 711 712 MethodHandle integerParseInt = MethodHandles.lookup().findStatic( 713 Integer.class, "parseInt", MethodType.methodType(int.class, String.class)); 714 715 bound = integerParseInt.bindTo("78452"); 716 int intValue = (int) bound.invoke(); 717 if (intValue != 78452) { 718 fail("Unexpected value: " + intValue); 719 } 720 } 721 722 public static String filterReturnValue_target(int a) { 723 return "ReturnValue" + a; 724 } 725 726 public static boolean filterReturnValue_filter(String value) { 727 return value.indexOf("42") != -1; 728 } 729 730 public static int filterReturnValue_intTarget(String a) { 731 return Integer.parseInt(a); 732 } 733 734 public static int filterReturnValue_intFilter(int b) { 735 return b + 1; 736 } 737 738 public static void filterReturnValue_voidTarget() { 739 } 740 741 public static int filterReturnValue_voidFilter() { 742 return 42; 743 } 744 745 public static void testFilterReturnValue() throws Throwable { 746 // A target that returns a reference. 747 { 748 final MethodHandle target = MethodHandles.lookup().findStatic(Main.class, 749 "filterReturnValue_target", MethodType.methodType(String.class, int.class)); 750 final MethodHandle filter = MethodHandles.lookup().findStatic(Main.class, 751 "filterReturnValue_filter", MethodType.methodType(boolean.class, String.class)); 752 753 MethodHandle adapter = MethodHandles.filterReturnValue(target, filter); 754 755 boolean value = (boolean) adapter.invoke((int) 42); 756 if (!value) { 757 fail("Unexpected value: " + value); 758 } 759 value = (boolean) adapter.invoke((int) 43); 760 if (value) { 761 fail("Unexpected value: " + value); 762 } 763 } 764 765 // A target that returns a primitive. 766 { 767 final MethodHandle target = MethodHandles.lookup().findStatic(Main.class, 768 "filterReturnValue_intTarget", MethodType.methodType(int.class, String.class)); 769 final MethodHandle filter = MethodHandles.lookup().findStatic(Main.class, 770 "filterReturnValue_intFilter", MethodType.methodType(int.class, int.class)); 771 772 MethodHandle adapter = MethodHandles.filterReturnValue(target, filter); 773 774 int value = (int) adapter.invoke("56"); 775 if (value != 57) { 776 fail("Unexpected value: " + value); 777 } 778 } 779 780 // A target that returns void. 781 { 782 final MethodHandle target = MethodHandles.lookup().findStatic(Main.class, 783 "filterReturnValue_voidTarget", MethodType.methodType(void.class)); 784 final MethodHandle filter = MethodHandles.lookup().findStatic(Main.class, 785 "filterReturnValue_voidFilter", MethodType.methodType(int.class)); 786 787 MethodHandle adapter = MethodHandles.filterReturnValue(target, filter); 788 789 int value = (int) adapter.invoke(); 790 if (value != 42) { 791 fail("Unexpected value: " + value); 792 } 793 } 794 } 795 796 public static void permuteArguments_callee(boolean a, byte b, char c, 797 short d, int e, long f, float g, double h) { 798 if (a == true && b == (byte) 'b' && c == 'c' && d == (short) 56 && 799 e == 78 && f == (long) 97 && g == 98.0f && f == 97.0) { 800 return; 801 } 802 803 fail("Unexpected arguments: " + a + ", " + b + ", " + c 804 + ", " + d + ", " + e + ", " + f + ", " + g + ", " + h); 805 } 806 807 public static void permuteArguments_boxingCallee(boolean a, Integer b) { 808 if (a && b.intValue() == 42) { 809 return; 810 } 811 812 fail("Unexpected arguments: " + a + ", " + b); 813 } 814 815 public static void testPermuteArguments() throws Throwable { 816 { 817 final MethodHandle target = MethodHandles.lookup().findStatic( 818 Main.class, "permuteArguments_callee", 819 MethodType.methodType(void.class, new Class<?>[] { 820 boolean.class, byte.class, char.class, short.class, int.class, 821 long.class, float.class, double.class })); 822 823 final MethodType newType = MethodType.methodType(void.class, new Class<?>[] { 824 double.class, float.class, long.class, int.class, short.class, char.class, 825 byte.class, boolean.class }); 826 827 final MethodHandle permutation = MethodHandles.permuteArguments( 828 target, newType, new int[] { 7, 6, 5, 4, 3, 2, 1, 0 }); 829 830 permutation.invoke((double) 97.0, (float) 98.0f, (long) 97, 78, 831 (short) 56, 'c', (byte) 'b', (boolean) true); 832 833 // The permutation array was not of the right length. 834 try { 835 MethodHandles.permuteArguments(target, newType, 836 new int[] { 7 }); 837 fail(); 838 } catch (IllegalArgumentException expected) { 839 } 840 841 // The permutation array has an element that's out of bounds 842 // (there's no argument with idx == 8). 843 try { 844 MethodHandles.permuteArguments(target, newType, 845 new int[] { 8, 6, 5, 4, 3, 2, 1, 0 }); 846 fail(); 847 } catch (IllegalArgumentException expected) { 848 } 849 850 // The permutation array maps to an incorrect type. 851 try { 852 MethodHandles.permuteArguments(target, newType, 853 new int[] { 7, 7, 5, 4, 3, 2, 1, 0 }); 854 fail(); 855 } catch (IllegalArgumentException expected) { 856 } 857 } 858 859 // Tests for reference arguments as well as permutations that 860 // repeat arguments. 861 { 862 final MethodHandle target = MethodHandles.lookup().findVirtual( 863 String.class, "concat", MethodType.methodType(String.class, String.class)); 864 865 final MethodType newType = MethodType.methodType(String.class, String.class, 866 String.class); 867 868 assertEquals("foobar", (String) target.invoke("foo", "bar")); 869 870 MethodHandle permutation = MethodHandles.permuteArguments(target, 871 newType, new int[] { 1, 0 }); 872 assertEquals("barfoo", (String) permutation.invoke("foo", "bar")); 873 874 permutation = MethodHandles.permuteArguments(target, newType, new int[] { 0, 0 }); 875 assertEquals("foofoo", (String) permutation.invoke("foo", "bar")); 876 877 permutation = MethodHandles.permuteArguments(target, newType, new int[] { 1, 1 }); 878 assertEquals("barbar", (String) permutation.invoke("foo", "bar")); 879 } 880 881 // Tests for boxing and unboxing. 882 { 883 final MethodHandle target = MethodHandles.lookup().findStatic( 884 Main.class, "permuteArguments_boxingCallee", 885 MethodType.methodType(void.class, new Class<?>[] { boolean.class, Integer.class })); 886 887 final MethodType newType = MethodType.methodType(void.class, 888 new Class<?>[] { Integer.class, boolean.class }); 889 890 MethodHandle permutation = MethodHandles.permuteArguments(target, 891 newType, new int[] { 1, 0 }); 892 893 permutation.invoke(42, true); 894 permutation.invoke(42, Boolean.TRUE); 895 permutation.invoke(Integer.valueOf(42), true); 896 permutation.invoke(Integer.valueOf(42), Boolean.TRUE); 897 } 898 } 899 900 private static Object returnBar() { 901 return "bar"; 902 } 903 904 public static void testInvokers() throws Throwable { 905 final MethodType targetType = MethodType.methodType(String.class, String.class); 906 final MethodHandle target = MethodHandles.lookup().findVirtual( 907 String.class, "concat", targetType); 908 909 MethodHandle invoker = MethodHandles.invoker(target.type()); 910 assertEquals("barbar", (String) invoker.invoke(target, "bar", "bar")); 911 assertEquals("barbar", (String) invoker.invoke(target, (Object) returnBar(), "bar")); 912 try { 913 String foo = (String) invoker.invoke(target, "bar", "bar", 24); 914 fail(); 915 } catch (WrongMethodTypeException expected) { 916 } 917 918 MethodHandle exactInvoker = MethodHandles.exactInvoker(target.type()); 919 assertEquals("barbar", (String) exactInvoker.invoke(target, "bar", "bar")); 920 try { 921 String foo = (String) exactInvoker.invoke(target, (Object) returnBar(), "bar"); 922 fail(); 923 } catch (WrongMethodTypeException expected) { 924 } 925 try { 926 String foo = (String) exactInvoker.invoke(target, "bar", "bar", 24); 927 fail(); 928 } catch (WrongMethodTypeException expected) { 929 } 930 } 931 932 public static int spreadReferences(String a, String b, String c) { 933 System.out.println("a: " + a + ", b:" + b + ", c: " + c); 934 return 42; 935 } 936 937 public static int spreadReferences_Unbox(String a, int b) { 938 System.out.println("a: " + a + ", b:" + b); 939 return 43; 940 } 941 942 public static void testSpreaders_reference() throws Throwable { 943 MethodType methodType = MethodType.methodType(int.class, 944 new Class<?>[] { String.class, String.class, String.class }); 945 MethodHandle delegate = MethodHandles.lookup().findStatic( 946 Main.class, "spreadReferences", methodType); 947 948 // Basic checks on array lengths. 949 // 950 // Array size = 0 951 MethodHandle mhAsSpreader = delegate.asSpreader(String[].class, 0); 952 int ret = (int) mhAsSpreader.invoke("a", "b", "c", new String[] {}); 953 assertEquals(42, ret); 954 // Array size = 1 955 mhAsSpreader = delegate.asSpreader(String[].class, 1); 956 ret = (int) mhAsSpreader.invoke("a", "b", new String[] { "c" }); 957 assertEquals(42, ret); 958 // Array size = 2 959 mhAsSpreader = delegate.asSpreader(String[].class, 2); 960 ret = (int) mhAsSpreader.invoke("a", new String[] { "b", "c" }); 961 assertEquals(42, ret); 962 // Array size = 3 963 mhAsSpreader = delegate.asSpreader(String[].class, 3); 964 ret = (int) mhAsSpreader.invoke(new String[] { "a", "b", "c"}); 965 assertEquals(42, ret); 966 967 // Exception case, array size = 4 is illegal. 968 try { 969 delegate.asSpreader(String[].class, 4); 970 fail(); 971 } catch (IllegalArgumentException expected) { 972 } 973 974 // Exception case, calling with an arg of the wrong size. 975 // Array size = 3 976 mhAsSpreader = delegate.asSpreader(String[].class, 3); 977 try { 978 ret = (int) mhAsSpreader.invoke(new String[] { "a", "b"}); 979 } catch (IllegalArgumentException expected) { 980 } 981 982 // Various other hijinks, pass as Object[] arrays, Object etc. 983 mhAsSpreader = delegate.asSpreader(Object[].class, 2); 984 ret = (int) mhAsSpreader.invoke("a", new String[] { "b", "c" }); 985 assertEquals(42, ret); 986 987 mhAsSpreader = delegate.asSpreader(Object[].class, 2); 988 ret = (int) mhAsSpreader.invoke("a", new Object[] { "b", "c" }); 989 assertEquals(42, ret); 990 991 mhAsSpreader = delegate.asSpreader(Object[].class, 2); 992 ret = (int) mhAsSpreader.invoke("a", (Object) new Object[] { "b", "c" }); 993 assertEquals(42, ret); 994 995 // Test implicit unboxing. 996 MethodType methodType2 = MethodType.methodType(int.class, 997 new Class<?>[] { String.class, int.class }); 998 MethodHandle delegate2 = MethodHandles.lookup().findStatic( 999 Main.class, "spreadReferences_Unbox", methodType2); 1000 1001 // .. with an Integer[] array. 1002 mhAsSpreader = delegate2.asSpreader(Integer[].class, 1); 1003 ret = (int) mhAsSpreader.invoke("a", new Integer[] { 43 }); 1004 assertEquals(43, ret); 1005 1006 // .. with an Integer[] array declared as an Object[] argument type. 1007 mhAsSpreader = delegate2.asSpreader(Object[].class, 1); 1008 ret = (int) mhAsSpreader.invoke("a", new Integer[] { 43 }); 1009 assertEquals(43, ret); 1010 1011 // .. with an Object[] array. 1012 mhAsSpreader = delegate2.asSpreader(Object[].class, 1); 1013 ret = (int) mhAsSpreader.invoke("a", new Object[] { Integer.valueOf(43)}); 1014 assertEquals(43, ret); 1015 1016 // -- Part 2-- 1017 // Run a subset of these tests on MethodHandles.spreadInvoker, which only accepts 1018 // a trailing argument type of Object[]. 1019 MethodHandle spreadInvoker = MethodHandles.spreadInvoker(methodType2, 1); 1020 ret = (int) spreadInvoker.invoke(delegate2, "a", new Object[] { Integer.valueOf(43)}); 1021 assertEquals(43, ret); 1022 1023 ret = (int) spreadInvoker.invoke(delegate2, "a", new Integer[] { 43 }); 1024 assertEquals(43, ret); 1025 1026 // NOTE: Annoyingly, the second argument here is leadingArgCount and not 1027 // arrayLength. 1028 spreadInvoker = MethodHandles.spreadInvoker(methodType, 3); 1029 ret = (int) spreadInvoker.invoke(delegate, "a", "b", "c", new String[] {}); 1030 assertEquals(42, ret); 1031 1032 spreadInvoker = MethodHandles.spreadInvoker(methodType, 0); 1033 ret = (int) spreadInvoker.invoke(delegate, new String[] { "a", "b", "c" }); 1034 assertEquals(42, ret); 1035 1036 // Exact invokes: Double check that the expected parameter type is 1037 // Object[] and not T[]. 1038 try { 1039 spreadInvoker.invokeExact(delegate, new String[] { "a", "b", "c" }); 1040 fail(); 1041 } catch (WrongMethodTypeException expected) { 1042 } 1043 1044 ret = (int) spreadInvoker.invoke(delegate, new Object[] { "a", "b", "c" }); 1045 assertEquals(42, ret); 1046 } 1047 1048 public static int spreadBoolean(String a, Boolean b, boolean c) { 1049 System.out.println("a: " + a + ", b:" + b + ", c: " + c); 1050 return 44; 1051 } 1052 1053 public static int spreadByte(String a, Byte b, byte c, 1054 short d, int e, long f, float g, double h) { 1055 System.out.println("a: " + a + ", b:" + b + ", c: " + c + 1056 ", d: " + d + ", e: " + e + ", f:" + f + ", g: " + g + 1057 ", h: " + h); 1058 return 45; 1059 } 1060 1061 public static int spreadChar(String a, Character b, char c, 1062 int d, long e, float f, double g) { 1063 System.out.println("a: " + a + ", b:" + b + ", c: " + c + 1064 ", d: " + d + ", e: " + e + ", f:" + f + ", g: " + g); 1065 return 46; 1066 } 1067 1068 public static int spreadShort(String a, Short b, short c, 1069 int d, long e, float f, double g) { 1070 System.out.println("a: " + a + ", b:" + b + ", c: " + c + 1071 ", d: " + d + ", e: " + e + ", f:" + f + ", g:" + g); 1072 return 47; 1073 } 1074 1075 public static int spreadInt(String a, Integer b, int c, 1076 long d, float e, double f) { 1077 System.out.println("a: " + a + ", b:" + b + ", c: " + c + 1078 ", d: " + d + ", e: " + e + ", f:" + f); 1079 return 48; 1080 } 1081 1082 public static int spreadLong(String a, Long b, long c, float d, double e) { 1083 System.out.println("a: " + a + ", b:" + b + ", c: " + c + 1084 ", d: " + d + ", e: " + e); 1085 return 49; 1086 } 1087 1088 public static int spreadFloat(String a, Float b, float c, double d) { 1089 System.out.println("a: " + a + ", b:" + b + ", c: " + c + ", d: " + d); 1090 return 50; 1091 } 1092 1093 public static int spreadDouble(String a, Double b, double c) { 1094 System.out.println("a: " + a + ", b:" + b + ", c: " + c); 1095 return 51; 1096 } 1097 1098 public static void testSpreaders_primitive() throws Throwable { 1099 // boolean[] 1100 // --------------------- 1101 MethodType type = MethodType.methodType(int.class, 1102 new Class<?>[] { String.class, Boolean.class, boolean.class }); 1103 MethodHandle delegate = MethodHandles.lookup().findStatic( 1104 Main.class, "spreadBoolean", type); 1105 1106 MethodHandle spreader = delegate.asSpreader(boolean[].class, 2); 1107 int ret = (int) spreader.invokeExact("a", new boolean[] { true, false }); 1108 assertEquals(44, ret); 1109 ret = (int) spreader.invoke("a", new boolean[] { true, false }); 1110 assertEquals(44, ret); 1111 1112 // boolean can't be cast to String (the first argument to the method). 1113 try { 1114 delegate.asSpreader(boolean[].class, 3); 1115 fail(); 1116 } catch (WrongMethodTypeException expected) { 1117 } 1118 1119 // int can't be cast to boolean to supply the last argument to the method. 1120 try { 1121 delegate.asSpreader(int[].class, 1); 1122 fail(); 1123 } catch (WrongMethodTypeException expected) { 1124 } 1125 1126 // byte[] 1127 // --------------------- 1128 type = MethodType.methodType(int.class, 1129 new Class<?>[] { 1130 String.class, Byte.class, byte.class, 1131 short.class, int.class, long.class, 1132 float.class, double.class }); 1133 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadByte", type); 1134 1135 spreader = delegate.asSpreader(byte[].class, 7); 1136 ret = (int) spreader.invokeExact("a", 1137 new byte[] { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 }); 1138 assertEquals(45, ret); 1139 ret = (int) spreader.invoke("a", 1140 new byte[] { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 }); 1141 assertEquals(45, ret); 1142 1143 // char[] 1144 // --------------------- 1145 type = MethodType.methodType(int.class, 1146 new Class<?>[] { 1147 String.class, Character.class,char.class, 1148 int.class, long.class, float.class, double.class }); 1149 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadChar", type); 1150 1151 spreader = delegate.asSpreader(char[].class, 6); 1152 ret = (int) spreader.invokeExact("a", 1153 new char[] { '1', '2', '3', '4', '5', '6' }); 1154 assertEquals(46, ret); 1155 ret = (int) spreader.invokeExact("a", 1156 new char[] { '1', '2', '3', '4', '5', '6' }); 1157 assertEquals(46, ret); 1158 1159 // short[] 1160 // --------------------- 1161 type = MethodType.methodType(int.class, 1162 new Class<?>[] { 1163 String.class, Short.class, short.class, 1164 int.class, long.class, float.class, double.class }); 1165 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadShort", type); 1166 1167 spreader = delegate.asSpreader(short[].class, 6); 1168 ret = (int) spreader.invokeExact("a", 1169 new short[] { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 }); 1170 assertEquals(47, ret); 1171 ret = (int) spreader.invoke("a", 1172 new short[] { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 }); 1173 assertEquals(47, ret); 1174 1175 // int[] 1176 // --------------------- 1177 type = MethodType.methodType(int.class, 1178 new Class<?>[] { 1179 String.class, Integer.class, int.class, 1180 long.class, float.class, double.class }); 1181 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadInt", type); 1182 1183 spreader = delegate.asSpreader(int[].class, 5); 1184 ret = (int) spreader.invokeExact("a", new int[] { 1, 2, 3, 4, 5 }); 1185 assertEquals(48, ret); 1186 ret = (int) spreader.invokeExact("a", new int[] { 1, 2, 3, 4, 5 }); 1187 assertEquals(48, ret); 1188 1189 // long[] 1190 // --------------------- 1191 type = MethodType.methodType(int.class, 1192 new Class<?>[] { 1193 String.class, Long.class, long.class, float.class, double.class }); 1194 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadLong", type); 1195 1196 spreader = delegate.asSpreader(long[].class, 4); 1197 ret = (int) spreader.invokeExact("a", 1198 new long[] { 0x1, 0x2, 0x3, 0x4 }); 1199 assertEquals(49, ret); 1200 ret = (int) spreader.invoke("a", 1201 new long[] { 0x1, 0x2, 0x3, 0x4 }); 1202 assertEquals(49, ret); 1203 1204 // float[] 1205 // --------------------- 1206 type = MethodType.methodType(int.class, 1207 new Class<?>[] { 1208 String.class, Float.class, float.class, double.class }); 1209 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadFloat", type); 1210 1211 spreader = delegate.asSpreader(float[].class, 3); 1212 ret = (int) spreader.invokeExact("a", 1213 new float[] { 1.0f, 2.0f, 3.0f }); 1214 assertEquals(50, ret); 1215 ret = (int) spreader.invokeExact("a", 1216 new float[] { 1.0f, 2.0f, 3.0f }); 1217 assertEquals(50, ret); 1218 1219 // double[] 1220 // --------------------- 1221 type = MethodType.methodType(int.class, 1222 new Class<?>[] { String.class, Double.class, double.class }); 1223 delegate = MethodHandles.lookup().findStatic(Main.class, "spreadDouble", type); 1224 1225 spreader = delegate.asSpreader(double[].class, 2); 1226 ret = (int) spreader.invokeExact("a", new double[] { 1.0, 2.0 }); 1227 assertEquals(51, ret); 1228 ret = (int) spreader.invokeExact("a", new double[] { 1.0, 2.0 }); 1229 assertEquals(51, ret); 1230 } 1231 1232 public static void testInvokeWithArguments() throws Throwable { 1233 MethodType methodType = MethodType.methodType(int.class, 1234 new Class<?>[] { String.class, String.class, String.class }); 1235 MethodHandle handle = MethodHandles.lookup().findStatic( 1236 Main.class, "spreadReferences", methodType); 1237 1238 Object ret = handle.invokeWithArguments(new Object[] { "a", "b", "c"}); 1239 assertEquals(42, (int) ret); 1240 handle.invokeWithArguments(new String[] { "a", "b", "c" }); 1241 assertEquals(42, (int) ret); 1242 1243 // Pass in an array that's too small. Should throw an IAE. 1244 try { 1245 handle.invokeWithArguments(new Object[] { "a", "b" }); 1246 fail(); 1247 } catch (IllegalArgumentException expected) { 1248 } catch (WrongMethodTypeException expected) { 1249 } 1250 1251 // Test implicit unboxing. 1252 MethodType methodType2 = MethodType.methodType(int.class, 1253 new Class<?>[] { String.class, int.class }); 1254 MethodHandle handle2 = MethodHandles.lookup().findStatic( 1255 Main.class, "spreadReferences_Unbox", methodType2); 1256 1257 ret = (int) handle2.invokeWithArguments(new Object[] { "a", 43 }); 1258 assertEquals(43, (int) ret); 1259 } 1260 1261 public static int collectBoolean(String a, boolean[] b) { 1262 System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]); 1263 return 44; 1264 } 1265 1266 public static int collectByte(String a, byte[] b) { 1267 System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]); 1268 return 45; 1269 } 1270 1271 public static int collectChar(String a, char[] b) { 1272 System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]); 1273 return 46; 1274 } 1275 1276 public static int collectShort(String a, short[] b) { 1277 System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]); 1278 return 47; 1279 } 1280 1281 public static int collectInt(String a, int[] b) { 1282 System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]); 1283 return 48; 1284 } 1285 1286 public static int collectLong(String a, long[] b) { 1287 System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]); 1288 return 49; 1289 } 1290 1291 public static int collectFloat(String a, float[] b) { 1292 System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]); 1293 return 50; 1294 } 1295 1296 public static int collectDouble(String a, double[] b) { 1297 System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]); 1298 return 51; 1299 } 1300 1301 public static int collectCharSequence(String a, CharSequence[] b) { 1302 System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]); 1303 return 99; 1304 } 1305 1306 public static void testAsCollector() throws Throwable { 1307 // Reference arrays. 1308 // ------------------- 1309 MethodHandle trailingRef = MethodHandles.lookup().findStatic( 1310 Main.class, "collectCharSequence", 1311 MethodType.methodType(int.class, String.class, CharSequence[].class)); 1312 1313 // int[] is not convertible to CharSequence[].class. 1314 try { 1315 trailingRef.asCollector(int[].class, 1); 1316 fail(); 1317 } catch (IllegalArgumentException expected) { 1318 } 1319 1320 // Object[] is not convertible to CharSequence[].class. 1321 try { 1322 trailingRef.asCollector(Object[].class, 1); 1323 fail(); 1324 } catch (IllegalArgumentException expected) { 1325 } 1326 1327 // String[].class is convertible to CharSequence.class 1328 MethodHandle collector = trailingRef.asCollector(String[].class, 2); 1329 assertEquals(99, (int) collector.invoke("a", "b", "c")); 1330 1331 // Too few arguments should fail with a WMTE. 1332 try { 1333 collector.invoke("a", "b"); 1334 fail(); 1335 } catch (WrongMethodTypeException expected) { 1336 } 1337 1338 // Too many arguments should fail with a WMTE. 1339 try { 1340 collector.invoke("a", "b", "c", "d"); 1341 fail(); 1342 } catch (WrongMethodTypeException expected) { 1343 } 1344 1345 // Sanity checks on other array types. 1346 1347 MethodHandle target = MethodHandles.lookup().findStatic( 1348 Main.class, "collectBoolean", 1349 MethodType.methodType(int.class, String.class, boolean[].class)); 1350 assertEquals(44, (int) target.asCollector(boolean[].class, 2).invoke("a", true, false)); 1351 1352 target = MethodHandles.lookup().findStatic(Main.class, "collectByte", 1353 MethodType.methodType(int.class, String.class, byte[].class)); 1354 assertEquals(45, (int) target.asCollector(byte[].class, 2).invoke("a", (byte) 1, (byte) 2)); 1355 1356 target = MethodHandles.lookup().findStatic(Main.class, "collectChar", 1357 MethodType.methodType(int.class, String.class, char[].class)); 1358 assertEquals(46, (int) target.asCollector(char[].class, 2).invoke("a", 'a', 'b')); 1359 1360 target = MethodHandles.lookup().findStatic(Main.class, "collectShort", 1361 MethodType.methodType(int.class, String.class, short[].class)); 1362 assertEquals(47, (int) target.asCollector(short[].class, 2).invoke("a", (short) 3, (short) 4)); 1363 1364 target = MethodHandles.lookup().findStatic(Main.class, "collectInt", 1365 MethodType.methodType(int.class, String.class, int[].class)); 1366 assertEquals(48, (int) target.asCollector(int[].class, 2).invoke("a", 42, 43)); 1367 1368 target = MethodHandles.lookup().findStatic(Main.class, "collectLong", 1369 MethodType.methodType(int.class, String.class, long[].class)); 1370 assertEquals(49, (int) target.asCollector(long[].class, 2).invoke("a", 100, 99)); 1371 1372 target = MethodHandles.lookup().findStatic(Main.class, "collectFloat", 1373 MethodType.methodType(int.class, String.class, float[].class)); 1374 assertEquals(50, (int) target.asCollector(float[].class, 2).invoke("a", 8.9f, 9.1f)); 1375 1376 target = MethodHandles.lookup().findStatic(Main.class, "collectDouble", 1377 MethodType.methodType(int.class, String.class, double[].class)); 1378 assertEquals(51, (int) target.asCollector(double[].class, 2).invoke("a", 6.7, 7.8)); 1379 } 1380 1381 public static String filter1(char a) { 1382 return String.valueOf(a); 1383 } 1384 1385 public static char filter2(String b) { 1386 return b.charAt(0); 1387 } 1388 1389 public static String badFilter1(char a, char b) { 1390 return "bad"; 1391 } 1392 1393 public static int filterTarget(String a, char b, String c, char d) { 1394 System.out.println("a: " + a + ", b: " + b + ", c:" + c + ", d:" + d); 1395 return 56; 1396 } 1397 1398 public static void testFilterArguments() throws Throwable { 1399 MethodHandle filter1 = MethodHandles.lookup().findStatic( 1400 Main.class, "filter1", MethodType.methodType(String.class, char.class)); 1401 MethodHandle filter2 = MethodHandles.lookup().findStatic( 1402 Main.class, "filter2", MethodType.methodType(char.class, String.class)); 1403 1404 MethodHandle target = MethodHandles.lookup().findStatic( 1405 Main.class, "filterTarget", MethodType.methodType(int.class, 1406 String.class, char.class, String.class, char.class)); 1407 1408 // In all the cases below, the values printed will be 'a', 'b', 'c', 'd'. 1409 1410 // Filter arguments [0, 1] - all other arguments are passed through 1411 // as is. 1412 MethodHandle adapter = MethodHandles.filterArguments( 1413 target, 0, filter1, filter2); 1414 assertEquals(56, (int) adapter.invokeExact('a', "bXXXX", "c", 'd')); 1415 1416 // Filter arguments [1, 2]. 1417 adapter = MethodHandles.filterArguments(target, 1, filter2, filter1); 1418 assertEquals(56, (int) adapter.invokeExact("a", "bXXXX", 'c', 'd')); 1419 1420 // Filter arguments [2, 3]. 1421 adapter = MethodHandles.filterArguments(target, 2, filter1, filter2); 1422 assertEquals(56, (int) adapter.invokeExact("a", 'b', 'c', "dXXXXX")); 1423 1424 // Try out a few error cases : 1425 1426 // The return types of the filter doesn't align with the expected argument 1427 // type of the target. 1428 try { 1429 adapter = MethodHandles.filterArguments(target, 2, filter2, filter1); 1430 fail(); 1431 } catch (IllegalArgumentException expected) { 1432 } 1433 1434 // There are more filters than arguments. 1435 try { 1436 adapter = MethodHandles.filterArguments(target, 3, filter2, filter1); 1437 fail(); 1438 } catch (IllegalArgumentException expected) { 1439 } 1440 1441 // We pass in an obviously bogus position. 1442 try { 1443 adapter = MethodHandles.filterArguments(target, -1, filter2, filter1); 1444 fail(); 1445 } catch (ArrayIndexOutOfBoundsException expected) { 1446 } 1447 1448 // We pass in a function that has more than one argument. 1449 MethodHandle badFilter1 = MethodHandles.lookup().findStatic( 1450 Main.class, "badFilter1", 1451 MethodType.methodType(String.class, char.class, char.class)); 1452 1453 try { 1454 adapter = MethodHandles.filterArguments(target, 0, badFilter1, filter2); 1455 fail(); 1456 } catch (IllegalArgumentException expected) { 1457 } 1458 } 1459 1460 static void voidFilter(char a, char b) { 1461 System.out.println("voidFilter"); 1462 } 1463 1464 static String filter(char a, char b) { 1465 return String.valueOf(a) + "+" + b; 1466 } 1467 1468 static char badFilter(char a, char b) { 1469 return 0; 1470 } 1471 1472 static int target(String a, String b, String c) { 1473 System.out.println("a: " + a + ", b: " + b + ", c: " + c); 1474 return 57; 1475 } 1476 1477 public static void testCollectArguments() throws Throwable { 1478 // Test non-void filters. 1479 MethodHandle filter = MethodHandles.lookup().findStatic( 1480 Main.class, "filter", 1481 MethodType.methodType(String.class, char.class, char.class)); 1482 1483 MethodHandle target = MethodHandles.lookup().findStatic( 1484 Main.class, "target", 1485 MethodType.methodType(int.class, String.class, String.class, String.class)); 1486 1487 // Filter at position 0. 1488 MethodHandle adapter = MethodHandles.collectArguments(target, 0, filter); 1489 assertEquals(57, (int) adapter.invokeExact('a', 'b', "c", "d")); 1490 1491 // Filter at position 1. 1492 adapter = MethodHandles.collectArguments(target, 1, filter); 1493 assertEquals(57, (int) adapter.invokeExact("a", 'b', 'c', "d")); 1494 1495 // Filter at position 2. 1496 adapter = MethodHandles.collectArguments(target, 2, filter); 1497 assertEquals(57, (int) adapter.invokeExact("a", "b", 'c', 'd')); 1498 1499 // Test void filters. Note that we're passing in one more argument 1500 // than usual because the filter returns nothing - we have to invoke with 1501 // the full set of filter args and the full set of target args. 1502 filter = MethodHandles.lookup().findStatic(Main.class, "voidFilter", 1503 MethodType.methodType(void.class, char.class, char.class)); 1504 adapter = MethodHandles.collectArguments(target, 0, filter); 1505 assertEquals(57, (int) adapter.invokeExact('a', 'b', "a", "b", "c")); 1506 1507 adapter = MethodHandles.collectArguments(target, 1, filter); 1508 assertEquals(57, (int) adapter.invokeExact("a", 'a', 'b', "b", "c")); 1509 1510 // Test out a few failure cases. 1511 filter = MethodHandles.lookup().findStatic( 1512 Main.class, "filter", 1513 MethodType.methodType(String.class, char.class, char.class)); 1514 1515 // Bogus filter position. 1516 try { 1517 adapter = MethodHandles.collectArguments(target, 3, filter); 1518 fail(); 1519 } catch (IndexOutOfBoundsException expected) { 1520 } 1521 1522 // Mismatch in filter return type. 1523 filter = MethodHandles.lookup().findStatic( 1524 Main.class, "badFilter", 1525 MethodType.methodType(char.class, char.class, char.class)); 1526 try { 1527 adapter = MethodHandles.collectArguments(target, 0, filter); 1528 fail(); 1529 } catch (IllegalArgumentException expected) { 1530 } 1531 } 1532 1533 static int insertReceiver(String a, int b, Integer c, String d) { 1534 System.out.println("a: " + a + ", b:" + b + ", c:" + c + ", d:" + d); 1535 return 73; 1536 } 1537 1538 public static void testInsertArguments() throws Throwable { 1539 MethodHandle target = MethodHandles.lookup().findStatic( 1540 Main.class, "insertReceiver", 1541 MethodType.methodType(int.class, 1542 String.class, int.class, Integer.class, String.class)); 1543 1544 // Basic single element array inserted at position 0. 1545 MethodHandle adapter = MethodHandles.insertArguments( 1546 target, 0, new Object[] { "foo" }); 1547 assertEquals(73, (int) adapter.invokeExact(45, Integer.valueOf(56), "bar")); 1548 1549 // Exercise unboxing. 1550 adapter = MethodHandles.insertArguments( 1551 target, 1, new Object[] { Integer.valueOf(56), 57 }); 1552 assertEquals(73, (int) adapter.invokeExact("foo", "bar")); 1553 1554 // Exercise a widening conversion. 1555 adapter = MethodHandles.insertArguments( 1556 target, 1, new Object[] { (short) 56, Integer.valueOf(57) }); 1557 assertEquals(73, (int) adapter.invokeExact("foo", "bar")); 1558 1559 // Insert an argument at the last position. 1560 adapter = MethodHandles.insertArguments( 1561 target, 3, new Object[] { "bar" }); 1562 assertEquals(73, (int) adapter.invokeExact("foo", 45, Integer.valueOf(46))); 1563 1564 // Exercise a few error cases. 1565 1566 // A reference type that can't be cast to another reference type. 1567 try { 1568 MethodHandles.insertArguments(target, 3, new Object[] { new Object() }); 1569 fail(); 1570 } catch (ClassCastException expected) { 1571 } 1572 1573 // A boxed type that can't be unboxed correctly. 1574 try { 1575 MethodHandles.insertArguments(target, 1, new Object[] { Long.valueOf(56) }); 1576 fail(); 1577 } catch (ClassCastException expected) { 1578 } 1579 } 1580 1581 public static String foldFilter(char a, char b) { 1582 return String.valueOf(a) + "+" + b; 1583 } 1584 1585 public static void voidFoldFilter(String e, char a, char b) { 1586 System.out.println(String.valueOf(a) + "+" + b); 1587 } 1588 1589 public static int foldTarget(String a, char b, char c, String d) { 1590 System.out.println("a: " + a + " ,b:" + b + " ,c:" + c + " ,d:" + d); 1591 return 89; 1592 } 1593 1594 public static void mismatchedVoidFilter(Integer a) { 1595 } 1596 1597 public static Integer mismatchedNonVoidFilter(char a, char b) { 1598 return null; 1599 } 1600 1601 public static void testFoldArguments() throws Throwable { 1602 // Test non-void filters. 1603 MethodHandle filter = MethodHandles.lookup().findStatic( 1604 Main.class, "foldFilter", 1605 MethodType.methodType(String.class, char.class, char.class)); 1606 1607 MethodHandle target = MethodHandles.lookup().findStatic( 1608 Main.class, "foldTarget", 1609 MethodType.methodType(int.class, String.class, 1610 char.class, char.class, String.class)); 1611 1612 // Folder with a non-void type. 1613 MethodHandle adapter = MethodHandles.foldArguments(target, filter); 1614 assertEquals(89, (int) adapter.invokeExact('c', 'd', "e")); 1615 1616 // Folder with a void type. 1617 filter = MethodHandles.lookup().findStatic( 1618 Main.class, "voidFoldFilter", 1619 MethodType.methodType(void.class, String.class, char.class, char.class)); 1620 adapter = MethodHandles.foldArguments(target, filter); 1621 assertEquals(89, (int) adapter.invokeExact("a", 'c', 'd', "e")); 1622 1623 // Test a few erroneous cases. 1624 1625 filter = MethodHandles.lookup().findStatic( 1626 Main.class, "mismatchedVoidFilter", 1627 MethodType.methodType(void.class, Integer.class)); 1628 try { 1629 adapter = MethodHandles.foldArguments(target, filter); 1630 fail(); 1631 } catch (IllegalArgumentException expected) { 1632 } 1633 1634 filter = MethodHandles.lookup().findStatic( 1635 Main.class, "mismatchedNonVoidFilter", 1636 MethodType.methodType(Integer.class, char.class, char.class)); 1637 try { 1638 adapter = MethodHandles.foldArguments(target, filter); 1639 fail(); 1640 } catch (IllegalArgumentException expected) { 1641 } 1642 } 1643 1644 public static void fail() { 1645 System.out.println("FAIL"); 1646 Thread.dumpStack(); 1647 } 1648 1649 public static void fail(String message) { 1650 System.out.println("fail: " + message); 1651 Thread.dumpStack(); 1652 } 1653 1654 public static void assertEquals(int i1, int i2) { 1655 if (i1 != i2) throw new AssertionError("Expected: " + i1 + " was " + i2); 1656 } 1657 1658 public static void assertEquals(String s1, String s2) { 1659 if (s1 == s2) { 1660 return; 1661 } 1662 1663 if (s1 != null && s2 != null && s1.equals(s2)) { 1664 return; 1665 } 1666 1667 throw new AssertionError("assertEquals s1: " + s1 + ", s2: " + s2); 1668 } 1669 } 1670