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