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.MethodHandleInfo; 19 import java.lang.invoke.MethodHandles; 20 import java.lang.invoke.MethodHandles.Lookup; 21 import java.lang.invoke.MethodType; 22 import java.lang.invoke.WrongMethodTypeException; 23 import java.lang.reflect.Constructor; 24 import java.lang.reflect.Field; 25 import java.lang.reflect.Method; 26 import java.nio.charset.Charset; 27 import java.nio.charset.StandardCharsets; 28 import java.util.ArrayList; 29 import java.util.Arrays; 30 import java.util.List; 31 32 public class Main { 33 34 public static class A { 35 public A() {} 36 37 public void foo() { 38 System.out.println("foo_A"); 39 } 40 41 public static final Lookup lookup = MethodHandles.lookup(); 42 } 43 44 public static class B extends A { 45 public void foo() { 46 System.out.println("foo_B"); 47 } 48 49 public static final Lookup lookup = MethodHandles.lookup(); 50 } 51 52 public static class C extends B { 53 public static final Lookup lookup = MethodHandles.lookup(); 54 } 55 56 public static class D { 57 private final void privateRyan() { 58 System.out.println("privateRyan_D"); 59 } 60 61 public static final Lookup lookup = MethodHandles.lookup(); 62 } 63 64 public static class E extends D { 65 public static final Lookup lookup = MethodHandles.lookup(); 66 } 67 68 public static void main(String[] args) throws Throwable { 69 testfindSpecial_invokeSuperBehaviour(); 70 testfindSpecial_invokeDirectBehaviour(); 71 testExceptionDetailMessages(); 72 testfindVirtual(); 73 testfindStatic(); 74 testUnreflects(); 75 testAsType(); 76 testConstructors(); 77 testStringConstructors(); 78 testReturnValueConversions(); 79 testVariableArity(); 80 testVariableArity_MethodHandles_bind(); 81 testRevealDirect(); 82 } 83 84 public static void testfindSpecial_invokeSuperBehaviour() throws Throwable { 85 // This is equivalent to an invoke-super instruction where the referrer 86 // is B.class. 87 MethodHandle mh1 = B.lookup.findSpecial(A.class /* refC */, "foo", 88 MethodType.methodType(void.class), B.class /* specialCaller */); 89 90 A aInstance = new A(); 91 B bInstance = new B(); 92 C cInstance = new C(); 93 94 // This should be as if an invoke-super was called from one of B's methods. 95 mh1.invokeExact(bInstance); 96 mh1.invoke(bInstance); 97 98 // This should not work. The receiver type in the handle will be suitably 99 // restricted to B and subclasses. 100 try { 101 mh1.invoke(aInstance); 102 System.out.println("mh1.invoke(aInstance) should not succeeed"); 103 } catch (ClassCastException expected) { 104 } 105 106 try { 107 mh1.invokeExact(aInstance); 108 System.out.println("mh1.invoke(aInstance) should not succeeed"); 109 } catch (WrongMethodTypeException expected) { 110 } 111 112 // This should *still* be as if an invoke-super was called from one of C's 113 // methods, despite the fact that we're operating on a C. 114 mh1.invoke(cInstance); 115 116 // Now that C is the special caller, the next invoke will call B.foo. 117 MethodHandle mh2 = C.lookup.findSpecial(A.class /* refC */, "foo", 118 MethodType.methodType(void.class), C.class /* specialCaller */); 119 mh2.invokeExact(cInstance); 120 121 // Shouldn't allow invoke-super semantics from an unrelated special caller. 122 try { 123 C.lookup.findSpecial(A.class, "foo", 124 MethodType.methodType(void.class), D.class /* specialCaller */); 125 System.out.println("findSpecial(A.class, foo, .. D.class) unexpectedly succeeded."); 126 } catch (IllegalAccessException expected) { 127 } 128 129 // Check return type matches for find. 130 try { 131 B.lookup.findSpecial(A.class /* refC */, "foo", 132 MethodType.methodType(int.class), B.class /* specialCaller */); 133 fail(); 134 } catch (NoSuchMethodException e) {} 135 // Check constructors 136 try { 137 B.lookup.findSpecial(A.class /* refC */, "<init>", 138 MethodType.methodType(void.class), B.class /* specialCaller */); 139 fail(); 140 } catch (NoSuchMethodException e) {} 141 } 142 143 public static void testfindSpecial_invokeDirectBehaviour() throws Throwable { 144 D dInstance = new D(); 145 146 MethodHandle mh3 = D.lookup.findSpecial(D.class, "privateRyan", 147 MethodType.methodType(void.class), D.class /* specialCaller */); 148 mh3.invoke(dInstance); 149 150 // The private method shouldn't be accessible from any special caller except 151 // itself... 152 try { 153 D.lookup.findSpecial(D.class, "privateRyan", MethodType.methodType(void.class), C.class); 154 System.out.println("findSpecial(privateRyan, C.class) unexpectedly succeeded"); 155 } catch (IllegalAccessException expected) { 156 } 157 158 // ... or from any lookup context except its own. 159 try { 160 E.lookup.findSpecial(D.class, "privateRyan", MethodType.methodType(void.class), E.class); 161 System.out.println("findSpecial(privateRyan, E.class) unexpectedly succeeded"); 162 } catch (IllegalAccessException expected) { 163 } 164 } 165 166 public static void testExceptionDetailMessages() throws Throwable { 167 MethodHandle handle = MethodHandles.lookup().findVirtual(String.class, "concat", 168 MethodType.methodType(String.class, String.class)); 169 170 try { 171 handle.invokeExact("a", new Object()); 172 System.out.println("invokeExact(\"a\", new Object()) unexpectedly succeeded."); 173 } catch (WrongMethodTypeException ex) { 174 System.out.println("Received exception: " + ex.getMessage()); 175 } 176 } 177 178 public interface Foo { 179 public String foo(); 180 } 181 182 public interface Bar extends Foo { 183 public String bar(); 184 } 185 186 public static abstract class BarAbstractSuper { 187 public abstract String abstractSuperPublicMethod(); 188 } 189 190 public static class BarSuper extends BarAbstractSuper { 191 public String superPublicMethod() { 192 return "superPublicMethod"; 193 } 194 195 protected String superProtectedMethod() { 196 return "superProtectedMethod"; 197 } 198 199 public String abstractSuperPublicMethod() { 200 return "abstractSuperPublicMethod"; 201 } 202 203 String superPackageMethod() { 204 return "superPackageMethod"; 205 } 206 } 207 208 public static class BarImpl extends BarSuper implements Bar { 209 public BarImpl() { 210 } 211 212 @Override 213 public String foo() { 214 return "foo"; 215 } 216 217 @Override 218 public String bar() { 219 return "bar"; 220 } 221 222 public String add(int x, int y) { 223 return Arrays.toString(new int[] { x, y }); 224 } 225 226 private String privateMethod() { return "privateMethod"; } 227 228 public static String staticMethod() { return staticString; } 229 230 private static String staticString; 231 232 { 233 // Static constructor 234 staticString = Long.toString(System.currentTimeMillis()); 235 } 236 237 static final MethodHandles.Lookup lookup = MethodHandles.lookup(); 238 } 239 240 public static void testfindVirtual() throws Throwable { 241 // Virtual lookups on static methods should not succeed. 242 try { 243 MethodHandles.lookup().findVirtual( 244 BarImpl.class, "staticMethod", MethodType.methodType(String.class)); 245 System.out.println("findVirtual(staticMethod) unexpectedly succeeded"); 246 } catch (IllegalAccessException expected) { 247 } 248 249 // Virtual lookups on private methods should not succeed, unless the Lookup 250 // context had sufficient privileges. 251 try { 252 MethodHandles.lookup().findVirtual( 253 BarImpl.class, "privateMethod", MethodType.methodType(String.class)); 254 System.out.println("findVirtual(privateMethod) unexpectedly succeeded"); 255 } catch (IllegalAccessException expected) { 256 } 257 258 // Virtual lookup on a private method with a context that *does* have sufficient 259 // privileges. 260 MethodHandle mh = BarImpl.lookup.findVirtual( 261 BarImpl.class, "privateMethod", MethodType.methodType(String.class)); 262 String str = (String) mh.invoke(new BarImpl()); 263 if (!"privateMethod".equals(str)) { 264 System.out.println("Unexpected return value for BarImpl#privateMethod: " + str); 265 } 266 267 // Find virtual must find interface methods defined by interfaces implemented 268 // by the class. 269 mh = MethodHandles.lookup().findVirtual(BarImpl.class, "foo", 270 MethodType.methodType(String.class)); 271 str = (String) mh.invoke(new BarImpl()); 272 if (!"foo".equals(str)) { 273 System.out.println("Unexpected return value for BarImpl#foo: " + str); 274 } 275 276 // Find virtual should check rtype. 277 try { 278 mh = MethodHandles.lookup().findVirtual(BarImpl.class, "foo", 279 MethodType.methodType(void.class)); 280 fail(); 281 } catch (NoSuchMethodException e) {} 282 283 // And ptypes 284 mh = MethodHandles.lookup().findVirtual( 285 BarImpl.class, "add", MethodType.methodType(String.class, int.class, int.class)); 286 try { 287 mh = MethodHandles.lookup().findVirtual( 288 BarImpl.class, "add", MethodType.methodType(String.class, Integer.class, int.class)); 289 } catch (NoSuchMethodException e) {} 290 291 // .. and their super-interfaces. 292 mh = MethodHandles.lookup().findVirtual(BarImpl.class, "bar", 293 MethodType.methodType(String.class)); 294 str = (String) mh.invoke(new BarImpl()); 295 if (!"bar".equals(str)) { 296 System.out.println("Unexpected return value for BarImpl#bar: " + str); 297 } 298 299 mh = MethodHandles.lookup().findVirtual(Bar.class, "bar", 300 MethodType.methodType(String.class)); 301 str = (String) mh.invoke(new BarImpl()); 302 if (!"bar".equals(str)) { 303 System.out.println("Unexpected return value for BarImpl#bar: " + str); 304 } 305 306 mh = MethodHandles.lookup().findVirtual(BarAbstractSuper.class, "abstractSuperPublicMethod", 307 MethodType.methodType(String.class)); 308 str = (String) mh.invoke(new BarImpl()); 309 if (!"abstractSuperPublicMethod".equals(str)) { 310 System.out.println("Unexpected return value for BarImpl#abstractSuperPublicMethod: " + str); 311 } 312 313 // We should also be able to lookup public / protected / package methods in 314 // the super class, given sufficient access privileges. 315 mh = MethodHandles.lookup().findVirtual(BarImpl.class, "superPublicMethod", 316 MethodType.methodType(String.class)); 317 str = (String) mh.invoke(new BarImpl()); 318 if (!"superPublicMethod".equals(str)) { 319 System.out.println("Unexpected return value for BarImpl#superPublicMethod: " + str); 320 } 321 322 mh = MethodHandles.lookup().findVirtual(BarImpl.class, "superProtectedMethod", 323 MethodType.methodType(String.class)); 324 str = (String) mh.invoke(new BarImpl()); 325 if (!"superProtectedMethod".equals(str)) { 326 System.out.println("Unexpected return value for BarImpl#superProtectedMethod: " + str); 327 } 328 329 mh = MethodHandles.lookup().findVirtual(BarImpl.class, "superPackageMethod", 330 MethodType.methodType(String.class)); 331 str = (String) mh.invoke(new BarImpl()); 332 if (!"superPackageMethod".equals(str)) { 333 System.out.println("Unexpected return value for BarImpl#superPackageMethod: " + str); 334 } 335 336 try { 337 MethodHandles.lookup().findVirtual(BarImpl.class, "<init>", 338 MethodType.methodType(void.class)); 339 fail(); 340 } catch (NoSuchMethodException e) {} 341 } 342 343 public static void testfindStatic() throws Throwable { 344 MethodHandles.lookup().findStatic(BarImpl.class, "staticMethod", 345 MethodType.methodType(String.class)); 346 try { 347 MethodHandles.lookup().findStatic(BarImpl.class, "staticMethod", 348 MethodType.methodType(void.class)); 349 fail(); 350 } catch (NoSuchMethodException e) {} 351 try { 352 MethodHandles.lookup().findStatic(BarImpl.class, "staticMethod", 353 MethodType.methodType(String.class, int.class)); 354 fail(); 355 } catch (NoSuchMethodException e) {} 356 try { 357 MethodHandles.lookup().findStatic(BarImpl.class, "<clinit>", 358 MethodType.methodType(void.class)); 359 fail(); 360 } catch (NoSuchMethodException e) {} 361 try { 362 MethodHandles.lookup().findStatic(BarImpl.class, "<init>", 363 MethodType.methodType(void.class)); 364 fail(); 365 } catch (NoSuchMethodException e) {} 366 } 367 368 static class UnreflectTester { 369 public String publicField; 370 private String privateField; 371 372 public static String publicStaticField = "publicStaticValue"; 373 private static String privateStaticField = "privateStaticValue"; 374 375 private UnreflectTester(String val) { 376 publicField = val; 377 privateField = val; 378 } 379 380 // NOTE: The boolean constructor argument only exists to give this a 381 // different signature. 382 public UnreflectTester(String val, boolean unused) { 383 this(val); 384 } 385 386 private static String privateStaticMethod() { 387 return "privateStaticMethod"; 388 } 389 390 private String privateMethod() { 391 return "privateMethod"; 392 } 393 394 public static String publicStaticMethod() { 395 return "publicStaticMethod"; 396 } 397 398 public String publicMethod() { 399 return "publicMethod"; 400 } 401 402 public String publicVarArgsMethod(String... args) { 403 return "publicVarArgsMethod"; 404 } 405 } 406 407 public static void testUnreflects() throws Throwable { 408 UnreflectTester instance = new UnreflectTester("unused"); 409 Method publicMethod = UnreflectTester.class.getMethod("publicMethod"); 410 411 MethodHandle mh = MethodHandles.lookup().unreflect(publicMethod); 412 assertEquals("publicMethod", (String) mh.invoke(instance)); 413 assertEquals("publicMethod", (String) mh.invokeExact(instance)); 414 415 Method publicStaticMethod = UnreflectTester.class.getMethod("publicStaticMethod"); 416 mh = MethodHandles.lookup().unreflect(publicStaticMethod); 417 assertEquals("publicStaticMethod", (String) mh.invoke()); 418 assertEquals("publicStaticMethod", (String) mh.invokeExact()); 419 420 Method privateMethod = UnreflectTester.class.getDeclaredMethod("privateMethod"); 421 try { 422 mh = MethodHandles.lookup().unreflect(privateMethod); 423 fail(); 424 } catch (IllegalAccessException expected) {} 425 426 privateMethod.setAccessible(true); 427 mh = MethodHandles.lookup().unreflect(privateMethod); 428 assertEquals("privateMethod", (String) mh.invoke(instance)); 429 assertEquals("privateMethod", (String) mh.invokeExact(instance)); 430 431 Method privateStaticMethod = UnreflectTester.class.getDeclaredMethod("privateStaticMethod"); 432 try { 433 mh = MethodHandles.lookup().unreflect(privateStaticMethod); 434 fail(); 435 } catch (IllegalAccessException expected) {} 436 437 privateStaticMethod.setAccessible(true); 438 mh = MethodHandles.lookup().unreflect(privateStaticMethod); 439 assertEquals("privateStaticMethod", (String) mh.invoke()); 440 assertEquals("privateStaticMethod", (String) mh.invokeExact()); 441 442 Constructor privateConstructor = UnreflectTester.class.getDeclaredConstructor(String.class); 443 try { 444 mh = MethodHandles.lookup().unreflectConstructor(privateConstructor); 445 fail(); 446 } catch (IllegalAccessException expected) {} 447 448 privateConstructor.setAccessible(true); 449 mh = MethodHandles.lookup().unreflectConstructor(privateConstructor); 450 instance = (UnreflectTester) mh.invokeExact("abc"); 451 assertEquals("abc", instance.publicField); 452 instance = (UnreflectTester) mh.invoke("def"); 453 assertEquals("def", instance.publicField); 454 Constructor publicConstructor = UnreflectTester.class.getConstructor(String.class, 455 boolean.class); 456 mh = MethodHandles.lookup().unreflectConstructor(publicConstructor); 457 instance = (UnreflectTester) mh.invokeExact("abc", false); 458 assertEquals("abc", instance.publicField); 459 instance = (UnreflectTester) mh.invoke("def", true); 460 assertEquals("def", instance.publicField); 461 462 // TODO(narayan): Non exact invokes for field sets/gets are not implemented yet. 463 // 464 // assertEquals("instanceValue", (String) mh.invoke(new UnreflectTester("instanceValue"))); 465 Field publicField = UnreflectTester.class.getField("publicField"); 466 mh = MethodHandles.lookup().unreflectGetter(publicField); 467 instance = new UnreflectTester("instanceValue"); 468 assertEquals("instanceValue", (String) mh.invokeExact(instance)); 469 470 mh = MethodHandles.lookup().unreflectSetter(publicField); 471 instance = new UnreflectTester("instanceValue"); 472 mh.invokeExact(instance, "updatedInstanceValue"); 473 assertEquals("updatedInstanceValue", instance.publicField); 474 475 Field publicStaticField = UnreflectTester.class.getField("publicStaticField"); 476 mh = MethodHandles.lookup().unreflectGetter(publicStaticField); 477 UnreflectTester.publicStaticField = "updatedStaticValue"; 478 assertEquals("updatedStaticValue", (String) mh.invokeExact()); 479 480 mh = MethodHandles.lookup().unreflectSetter(publicStaticField); 481 UnreflectTester.publicStaticField = "updatedStaticValue"; 482 mh.invokeExact("updatedStaticValue2"); 483 assertEquals("updatedStaticValue2", UnreflectTester.publicStaticField); 484 485 Field privateField = UnreflectTester.class.getDeclaredField("privateField"); 486 try { 487 mh = MethodHandles.lookup().unreflectGetter(privateField); 488 fail(); 489 } catch (IllegalAccessException expected) { 490 } 491 try { 492 mh = MethodHandles.lookup().unreflectSetter(privateField); 493 fail(); 494 } catch (IllegalAccessException expected) { 495 } 496 497 privateField.setAccessible(true); 498 499 mh = MethodHandles.lookup().unreflectGetter(privateField); 500 instance = new UnreflectTester("instanceValue"); 501 assertEquals("instanceValue", (String) mh.invokeExact(instance)); 502 503 mh = MethodHandles.lookup().unreflectSetter(privateField); 504 instance = new UnreflectTester("instanceValue"); 505 mh.invokeExact(instance, "updatedInstanceValue"); 506 assertEquals("updatedInstanceValue", instance.privateField); 507 508 Field privateStaticField = UnreflectTester.class.getDeclaredField("privateStaticField"); 509 try { 510 mh = MethodHandles.lookup().unreflectGetter(privateStaticField); 511 fail(); 512 } catch (IllegalAccessException expected) { 513 } 514 try { 515 mh = MethodHandles.lookup().unreflectSetter(privateStaticField); 516 fail(); 517 } catch (IllegalAccessException expected) { 518 } 519 520 privateStaticField.setAccessible(true); 521 mh = MethodHandles.lookup().unreflectGetter(privateStaticField); 522 privateStaticField.set(null, "updatedStaticValue"); 523 assertEquals("updatedStaticValue", (String) mh.invokeExact()); 524 525 mh = MethodHandles.lookup().unreflectSetter(privateStaticField); 526 privateStaticField.set(null, "updatedStaticValue"); 527 mh.invokeExact("updatedStaticValue2"); 528 assertEquals("updatedStaticValue2", (String) privateStaticField.get(null)); 529 } 530 531 // This method only exists to fool Jack's handling of types. See b/32536744. 532 public static CharSequence getSequence() { 533 return "foo"; 534 } 535 536 public static void testAsType() throws Throwable { 537 // The type of this handle is (String, String)String. 538 MethodHandle mh = MethodHandles.lookup().findVirtual(String.class, 539 "concat", MethodType.methodType(String.class, String.class)); 540 541 // Change it to (CharSequence, String)Object. 542 MethodHandle asType = mh.asType( 543 MethodType.methodType(Object.class, CharSequence.class, String.class)); 544 545 Object obj = asType.invokeExact((CharSequence) getSequence(), "bar"); 546 assertEquals("foobar", (String) obj); 547 548 // Should fail due to a wrong return type. 549 try { 550 String str = (String) asType.invokeExact((CharSequence) getSequence(), "bar"); 551 fail(); 552 } catch (WrongMethodTypeException expected) { 553 } 554 555 // Should fail due to a wrong argument type (String instead of Charsequence). 556 try { 557 String str = (String) asType.invokeExact("baz", "bar"); 558 fail(); 559 } catch (WrongMethodTypeException expected) { 560 } 561 562 // Calls to asType should fail if the types are not convertible. 563 // 564 // Bad return type conversion. 565 try { 566 mh.asType(MethodType.methodType(int.class, String.class, String.class)); 567 fail(); 568 } catch (WrongMethodTypeException expected) { 569 } 570 571 // Bad argument conversion. 572 try { 573 mh.asType(MethodType.methodType(String.class, int.class, String.class)); 574 fail(); 575 } catch (WrongMethodTypeException expected) { 576 } 577 } 578 579 public static void assertTrue(boolean value) { 580 if (!value) { 581 throw new AssertionError("assertTrue value: " + value); 582 } 583 } 584 585 public static void assertFalse(boolean value) { 586 if (value) { 587 throw new AssertionError("assertTrue value: " + value); 588 } 589 } 590 591 public static void assertEquals(int i1, int i2) { 592 if (i1 == i2) { return; } 593 throw new AssertionError("assertEquals i1: " + i1 + ", i2: " + i2); 594 } 595 596 public static void assertEquals(long i1, long i2) { 597 if (i1 == i2) { return; } 598 throw new AssertionError("assertEquals l1: " + i1 + ", l2: " + i2); 599 } 600 601 public static void assertEquals(Object o, Object p) { 602 if (o == p) { return; } 603 if (o != null && p != null && o.equals(p)) { return; } 604 throw new AssertionError("assertEquals: o1: " + o + ", o2: " + p); 605 } 606 607 public static void assertEquals(String s1, String s2) { 608 if (s1 == s2) { 609 return; 610 } 611 612 if (s1 != null && s2 != null && s1.equals(s2)) { 613 return; 614 } 615 616 throw new AssertionError("assertEquals s1: " + s1 + ", s2: " + s2); 617 } 618 619 public static void fail() { 620 System.out.println("fail"); 621 Thread.dumpStack(); 622 } 623 624 public static void fail(String message) { 625 System.out.println("fail: " + message); 626 Thread.dumpStack(); 627 } 628 629 public static void testConstructors() throws Throwable { 630 MethodHandle mh = 631 MethodHandles.lookup().findConstructor(Float.class, 632 MethodType.methodType(void.class, 633 float.class)); 634 Float value = (Float) mh.invokeExact(0.33f); 635 if (value.floatValue() != 0.33f) { 636 fail("Unexpected float value from invokeExact " + value.floatValue()); 637 } 638 639 value = (Float) mh.invoke(3.34f); 640 if (value.floatValue() != 3.34f) { 641 fail("Unexpected float value from invoke " + value.floatValue()); 642 } 643 644 mh = MethodHandles.lookup().findConstructor(Double.class, 645 MethodType.methodType(void.class, String.class)); 646 Double d = (Double) mh.invoke("8.45e3"); 647 if (d.doubleValue() != 8.45e3) { 648 fail("Unexpected double value from Double(String) " + value.doubleValue()); 649 } 650 651 mh = MethodHandles.lookup().findConstructor(Double.class, 652 MethodType.methodType(void.class, double.class)); 653 d = (Double) mh.invoke(8.45e3); 654 if (d.doubleValue() != 8.45e3) { 655 fail("Unexpected double value from Double(double) " + value.doubleValue()); 656 } 657 658 // Primitive type 659 try { 660 mh = MethodHandles.lookup().findConstructor(int.class, MethodType.methodType(void.class)); 661 fail("Unexpected lookup success for primitive constructor"); 662 } catch (NoSuchMethodException e) {} 663 664 // Interface 665 try { 666 mh = MethodHandles.lookup().findConstructor(Readable.class, 667 MethodType.methodType(void.class)); 668 fail("Unexpected lookup success for interface constructor"); 669 } catch (NoSuchMethodException e) {} 670 671 // Abstract 672 mh = MethodHandles.lookup().findConstructor(Process.class, MethodType.methodType(void.class)); 673 try { 674 mh.invoke(); 675 fail("Unexpected ability to instantiate an abstract class"); 676 } catch (InstantiationException e) {} 677 678 // Non-existent 679 try { 680 MethodHandle bad = MethodHandles.lookup().findConstructor( 681 String.class, MethodType.methodType(String.class, Float.class)); 682 fail("Unexpected success for non-existent constructor"); 683 } catch (NoSuchMethodException e) {} 684 685 // Non-void constructor search. (I)I instead of (I)V. 686 try { 687 MethodHandle foo = MethodHandles.lookup().findConstructor( 688 Integer.class, MethodType.methodType(Integer.class, Integer.class)); 689 fail("Unexpected success for non-void type for findConstructor"); 690 } catch (NoSuchMethodException e) {} 691 692 // Array class constructor. 693 try { 694 MethodHandle foo = MethodHandles.lookup().findConstructor( 695 Object[].class, MethodType.methodType(void.class)); 696 fail("Unexpected success for array class type for findConstructor"); 697 } catch (NoSuchMethodException e) {} 698 } 699 700 public static void testStringConstructors() throws Throwable { 701 final String testPattern = "The system as we know it is broken"; 702 703 // String() 704 MethodHandle mh = MethodHandles.lookup().findConstructor( 705 String.class, MethodType.methodType(void.class)); 706 String s = (String) mh.invokeExact(); 707 if (!s.equals("")) { 708 fail("Unexpected empty string constructor result: '" + s + "'"); 709 } 710 711 // String(String) 712 mh = MethodHandles.lookup().findConstructor( 713 String.class, MethodType.methodType(void.class, String.class)); 714 s = (String) mh.invokeExact(testPattern); 715 if (!s.equals(testPattern)) { 716 fail("Unexpected string constructor result: '" + s + "'"); 717 } 718 719 // String(char[]) 720 mh = MethodHandles.lookup().findConstructor( 721 String.class, MethodType.methodType(void.class, char[].class)); 722 s = (String) mh.invokeExact(testPattern.toCharArray()); 723 if (!s.equals(testPattern)) { 724 fail("Unexpected string constructor result: '" + s + "'"); 725 } 726 727 // String(char[], int, int) 728 mh = MethodHandles.lookup().findConstructor( 729 String.class, MethodType.methodType(void.class, char[].class, int.class, int.class)); 730 s = (String) mh.invokeExact(new char [] { 'a', 'b', 'c', 'd', 'e'}, 2, 3); 731 if (!s.equals("cde")) { 732 fail("Unexpected string constructor result: '" + s + "'"); 733 } 734 735 // String(int[] codePoints, int offset, int count) 736 StringBuffer sb = new StringBuffer(testPattern); 737 int[] codePoints = new int[sb.codePointCount(0, sb.length())]; 738 for (int i = 0; i < sb.length(); ++i) { 739 codePoints[i] = sb.codePointAt(i); 740 } 741 mh = MethodHandles.lookup().findConstructor( 742 String.class, MethodType.methodType(void.class, int[].class, int.class, int.class)); 743 s = (String) mh.invokeExact(codePoints, 0, codePoints.length); 744 if (!s.equals(testPattern)) { 745 fail("Unexpected string constructor result: '" + s + "'"); 746 } 747 748 // String(byte ascii[], int hibyte, int offset, int count) 749 byte [] ascii = testPattern.getBytes(StandardCharsets.US_ASCII); 750 mh = MethodHandles.lookup().findConstructor( 751 String.class, MethodType.methodType(void.class, byte[].class, int.class, int.class)); 752 s = (String) mh.invokeExact(ascii, 0, ascii.length); 753 if (!s.equals(testPattern)) { 754 fail("Unexpected string constructor result: '" + s + "'"); 755 } 756 757 // String(byte bytes[], int offset, int length, String charsetName) 758 mh = MethodHandles.lookup().findConstructor( 759 String.class, 760 MethodType.methodType(void.class, byte[].class, int.class, int.class, String.class)); 761 s = (String) mh.invokeExact(ascii, 0, 5, StandardCharsets.US_ASCII.name()); 762 if (!s.equals(testPattern.substring(0, 5))) { 763 fail("Unexpected string constructor result: '" + s + "'"); 764 } 765 766 // String(byte bytes[], int offset, int length, Charset charset) 767 mh = MethodHandles.lookup().findConstructor( 768 String.class, 769 MethodType.methodType(void.class, byte[].class, int.class, int.class, Charset.class)); 770 s = (String) mh.invokeExact(ascii, 0, 5, StandardCharsets.US_ASCII); 771 if (!s.equals(testPattern.substring(0, 5))) { 772 fail("Unexpected string constructor result: '" + s + "'"); 773 } 774 775 // String(byte bytes[], String charsetName) 776 mh = MethodHandles.lookup().findConstructor( 777 String.class, 778 MethodType.methodType(void.class, byte[].class, String.class)); 779 s = (String) mh.invokeExact(ascii, StandardCharsets.US_ASCII.name()); 780 if (!s.equals(testPattern)) { 781 fail("Unexpected string constructor result: '" + s + "'"); 782 } 783 784 // String(byte bytes[], Charset charset) 785 mh = MethodHandles.lookup().findConstructor( 786 String.class, MethodType.methodType(void.class, byte[].class, Charset.class)); 787 s = (String) mh.invokeExact(ascii, StandardCharsets.US_ASCII); 788 if (!s.equals(testPattern)) { 789 fail("Unexpected string constructor result: '" + s + "'"); 790 } 791 792 // String(byte bytes[], int offset, int length) 793 mh = MethodHandles.lookup().findConstructor( 794 String.class, MethodType.methodType(void.class, byte[].class, int.class, int.class)); 795 s = (String) mh.invokeExact(ascii, 1, ascii.length - 2); 796 s = testPattern.charAt(0) + s + testPattern.charAt(testPattern.length() - 1); 797 if (!s.equals(testPattern)) { 798 fail("Unexpected string constructor result: '" + s + "'"); 799 } 800 801 // String(byte bytes[]) 802 mh = MethodHandles.lookup().findConstructor( 803 String.class, MethodType.methodType(void.class, byte[].class)); 804 s = (String) mh.invokeExact(ascii); 805 if (!s.equals(testPattern)) { 806 fail("Unexpected string constructor result: '" + s + "'"); 807 } 808 809 // String(StringBuffer buffer) 810 mh = MethodHandles.lookup().findConstructor( 811 String.class, MethodType.methodType(void.class, StringBuffer.class)); 812 s = (String) mh.invokeExact(sb); 813 if (!s.equals(testPattern)) { 814 fail("Unexpected string constructor result: '" + s + "'"); 815 } 816 817 System.out.println("String constructors done."); 818 } 819 820 private static void testReferenceReturnValueConversions() throws Throwable { 821 MethodHandle mh = MethodHandles.lookup().findStatic( 822 Float.class, "valueOf", MethodType.methodType(Float.class, String.class)); 823 824 // No conversion 825 Float f = (Float) mh.invokeExact("1.375"); 826 if (f.floatValue() != 1.375) { 827 fail(); 828 } 829 f = (Float) mh.invoke("1.875"); 830 if (f.floatValue() != 1.875) { 831 fail(); 832 } 833 834 // Bad conversion 835 try { 836 int i = (int) mh.invokeExact("7.77"); 837 fail(); 838 } catch (WrongMethodTypeException e) {} 839 840 try { 841 int i = (int) mh.invoke("7.77"); 842 fail(); 843 } catch (WrongMethodTypeException e) {} 844 845 // Assignment to super-class. 846 Number n = (Number) mh.invoke("1.11"); 847 try { 848 Number o = (Number) mh.invokeExact("1.11"); 849 fail(); 850 } catch (WrongMethodTypeException e) {} 851 852 // Assignment to widened boxed primitive class. 853 try { 854 Double u = (Double) mh.invoke("1.11"); 855 fail(); 856 } catch (ClassCastException e) {} 857 858 try { 859 Double v = (Double) mh.invokeExact("1.11"); 860 fail(); 861 } catch (WrongMethodTypeException e) {} 862 863 // Unboxed 864 float p = (float) mh.invoke("1.11"); 865 if (p != 1.11f) { 866 fail(); 867 } 868 869 // Unboxed and widened 870 double d = (double) mh.invoke("2.5"); 871 if (d != 2.5) { 872 fail(); 873 } 874 875 // Interface 876 Comparable<Float> c = (Comparable<Float>) mh.invoke("2.125"); 877 if (c.compareTo(new Float(2.125f)) != 0) { 878 fail(); 879 } 880 881 System.out.println("testReferenceReturnValueConversions done."); 882 } 883 884 private static void testPrimitiveReturnValueConversions() throws Throwable { 885 MethodHandle mh = MethodHandles.lookup().findStatic( 886 Math.class, "min", MethodType.methodType(int.class, int.class, int.class)); 887 888 final int SMALL = -8972; 889 final int LARGE = 7932529; 890 891 // No conversion 892 if ((int) mh.invokeExact(LARGE, SMALL) != SMALL) { 893 fail(); 894 } else if ((int) mh.invoke(LARGE, SMALL) != SMALL) { 895 fail(); 896 } else if ((int) mh.invokeExact(SMALL, LARGE) != SMALL) { 897 fail(); 898 } else if ((int) mh.invoke(SMALL, LARGE) != SMALL) { 899 fail(); 900 } 901 902 // int -> long 903 try { 904 if ((long) mh.invokeExact(LARGE, SMALL) != (long) SMALL) {} 905 fail(); 906 } catch (WrongMethodTypeException e) {} 907 908 if ((long) mh.invoke(LARGE, SMALL) != (long) SMALL) { 909 fail(); 910 } 911 912 // int -> short 913 try { 914 if ((short) mh.invokeExact(LARGE, SMALL) != (short) SMALL) {} 915 fail(); 916 } catch (WrongMethodTypeException e) {} 917 918 try { 919 if ((short) mh.invoke(LARGE, SMALL) != (short) SMALL) { 920 fail(); 921 } 922 } catch (WrongMethodTypeException e) {} 923 924 // int -> Integer 925 try { 926 if (!((Integer) mh.invokeExact(LARGE, SMALL)).equals(new Integer(SMALL))) {} 927 fail(); 928 } catch (WrongMethodTypeException e) {} 929 930 if (!((Integer) mh.invoke(LARGE, SMALL)).equals(new Integer(SMALL))) { 931 fail(); 932 } 933 934 // int -> Long 935 try { 936 Long l = (Long) mh.invokeExact(LARGE, SMALL); 937 fail(); 938 } catch (WrongMethodTypeException e) {} 939 940 try { 941 Long l = (Long) mh.invoke(LARGE, SMALL); 942 fail(); 943 } catch (WrongMethodTypeException e) {} 944 945 // int -> Short 946 try { 947 Short s = (Short) mh.invokeExact(LARGE, SMALL); 948 fail(); 949 } catch (WrongMethodTypeException e) {} 950 951 try { 952 Short s = (Short) mh.invoke(LARGE, SMALL); 953 fail(); 954 } catch (WrongMethodTypeException e) {} 955 956 // int -> Process 957 try { 958 Process p = (Process) mh.invokeExact(LARGE, SMALL); 959 fail(); 960 } catch (WrongMethodTypeException e) {} 961 962 try { 963 Process p = (Process) mh.invoke(LARGE, SMALL); 964 fail(); 965 } catch (WrongMethodTypeException e) {} 966 967 // void -> Object 968 mh = MethodHandles.lookup().findStatic(System.class, "gc", MethodType.methodType(void.class)); 969 Object o = (Object) mh.invoke(); 970 if (o != null) fail(); 971 972 // void -> long 973 long l = (long) mh.invoke(); 974 if (l != 0) fail(); 975 976 // boolean -> Boolean 977 mh = MethodHandles.lookup().findStatic(Boolean.class, "parseBoolean", 978 MethodType.methodType(boolean.class, String.class)); 979 Boolean z = (Boolean) mh.invoke("True"); 980 if (!z.booleanValue()) fail(); 981 982 // boolean -> int 983 try { 984 int dummy = (int) mh.invoke("True"); 985 fail(); 986 } catch (WrongMethodTypeException e) {} 987 988 // boolean -> Integer 989 try { 990 Integer dummy = (Integer) mh.invoke("True"); 991 fail(); 992 } catch (WrongMethodTypeException e) {} 993 994 // Boolean -> boolean 995 mh = MethodHandles.lookup().findStatic(Boolean.class, "valueOf", 996 MethodType.methodType(Boolean.class, boolean.class)); 997 boolean w = (boolean) mh.invoke(false); 998 if (w) fail(); 999 1000 // Boolean -> int 1001 try { 1002 int dummy = (int) mh.invoke(false); 1003 fail(); 1004 } catch (WrongMethodTypeException e) {} 1005 1006 // Boolean -> Integer 1007 try { 1008 Integer dummy = (Integer) mh.invoke("True"); 1009 fail(); 1010 } catch (WrongMethodTypeException e) {} 1011 1012 System.out.println("testPrimitiveReturnValueConversions done."); 1013 } 1014 1015 public static void testReturnValueConversions() throws Throwable { 1016 testReferenceReturnValueConversions(); 1017 testPrimitiveReturnValueConversions(); 1018 } 1019 1020 public static class BaseVariableArityTester { 1021 public String update(Float f0, Float... floats) { 1022 return "base " + f0 + ", " + Arrays.toString(floats); 1023 } 1024 } 1025 1026 public static class VariableArityTester extends BaseVariableArityTester { 1027 private String lastResult; 1028 1029 // Constructors 1030 public VariableArityTester() {} 1031 public VariableArityTester(boolean... booleans) { update(booleans); } 1032 public VariableArityTester(byte... bytes) { update(bytes); } 1033 public VariableArityTester(char... chars) { update(chars); } 1034 public VariableArityTester(short... shorts) { update(shorts); } 1035 public VariableArityTester(int... ints) { update(ints); } 1036 public VariableArityTester(long... longs) { update(longs); } 1037 public VariableArityTester(float... floats) { update(floats); } 1038 public VariableArityTester(double... doubles) { update(doubles); } 1039 public VariableArityTester(Float f0, Float... floats) { update(f0, floats); } 1040 public VariableArityTester(String s0, String... strings) { update(s0, strings); } 1041 public VariableArityTester(char c, Number... numbers) { update(c, numbers); } 1042 @SafeVarargs 1043 public VariableArityTester(ArrayList<Integer> l0, ArrayList<Integer>... lists) { 1044 update(l0, lists); 1045 } 1046 public VariableArityTester(List l0, List... lists) { update(l0, lists); } 1047 1048 // Methods 1049 public String update(boolean... booleans) { return lastResult = tally(booleans); } 1050 public String update(byte... bytes) { return lastResult = tally(bytes); } 1051 public String update(char... chars) { return lastResult = tally(chars); } 1052 public String update(short... shorts) { return lastResult = tally(shorts); } 1053 public String update(int... ints) { 1054 lastResult = tally(ints); 1055 return lastResult; 1056 } 1057 public String update(long... longs) { return lastResult = tally(longs); } 1058 public String update(float... floats) { return lastResult = tally(floats); } 1059 public String update(double... doubles) { return lastResult = tally(doubles); } 1060 @Override 1061 public String update(Float f0, Float... floats) { return lastResult = tally(f0, floats); } 1062 public String update(String s0, String... strings) { return lastResult = tally(s0, strings); } 1063 public String update(char c, Number... numbers) { return lastResult = tally(c, numbers); } 1064 @SafeVarargs 1065 public final String update(ArrayList<Integer> l0, ArrayList<Integer>... lists) { 1066 lastResult = tally(l0, lists); 1067 return lastResult; 1068 } 1069 public String update(List l0, List... lists) { return lastResult = tally(l0, lists); } 1070 1071 public String arrayMethod(Object[] o) { 1072 return Arrays.deepToString(o); 1073 } 1074 1075 public String lastResult() { return lastResult; } 1076 1077 // Static Methods 1078 public static String tally(boolean... booleans) { return Arrays.toString(booleans); } 1079 public static String tally(byte... bytes) { return Arrays.toString(bytes); } 1080 public static String tally(char... chars) { return Arrays.toString(chars); } 1081 public static String tally(short... shorts) { return Arrays.toString(shorts); } 1082 public static String tally(int... ints) { return Arrays.toString(ints); } 1083 public static String tally(long... longs) { return Arrays.toString(longs); } 1084 public static String tally(float... floats) { return Arrays.toString(floats); } 1085 public static String tally(double... doubles) { return Arrays.toString(doubles); } 1086 public static String tally(Float f0, Float... floats) { 1087 return f0 + ", " + Arrays.toString(floats); 1088 } 1089 public static String tally(String s0, String... strings) { 1090 return s0 + ", " + Arrays.toString(strings); 1091 } 1092 public static String tally(char c, Number... numbers) { 1093 return c + ", " + Arrays.toString(numbers); 1094 } 1095 @SafeVarargs 1096 public static String tally(ArrayList<Integer> l0, ArrayList<Integer>... lists) { 1097 return Arrays.toString(l0.toArray()) + ", " + Arrays.deepToString(lists); 1098 } 1099 public static String tally(List l0, List... lists) { 1100 return Arrays.deepToString(l0.toArray()) + ", " + Arrays.deepToString(lists); 1101 } 1102 public static void foo(int... ints) { System.out.println(Arrays.toString(ints)); } 1103 public static long sumToPrimitive(int... ints) { 1104 long result = 0; 1105 for (int i : ints) result += i; 1106 return result; 1107 } 1108 public static Long sumToReference(int... ints) { 1109 System.out.println("Hi"); 1110 return new Long(sumToPrimitive(ints)); 1111 } 1112 public static MethodHandles.Lookup lookup() { 1113 return MethodHandles.lookup(); 1114 } 1115 } 1116 1117 // This method only exists to fool Jack's handling of types. See b/32536744. 1118 public static Object getAsObject(String[] strings) { 1119 return (Object) strings; 1120 } 1121 1122 public static void testVariableArity() throws Throwable { 1123 MethodHandle mh; 1124 VariableArityTester vat = new VariableArityTester(); 1125 1126 assertEquals("[1]", vat.update(1)); 1127 assertEquals("[1, 1]", vat.update(1, 1)); 1128 assertEquals("[1, 1, 1]", vat.update(1, 1, 1)); 1129 1130 // Methods - boolean 1131 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1132 MethodType.methodType(String.class, boolean[].class)); 1133 assertTrue(mh.isVarargsCollector()); 1134 assertFalse(mh.asFixedArity().isVarargsCollector()); 1135 assertEquals("[]", mh.invoke(vat)); 1136 assertEquals("[true, false, true]", mh.invoke(vat, true, false, true)); 1137 assertEquals("[true, false, true]", mh.invoke(vat, new boolean[] { true, false, true})); 1138 assertEquals("[false, true]", mh.invoke(vat, Boolean.valueOf(false), Boolean.valueOf(true))); 1139 try { 1140 mh.invoke(vat, true, true, 0); 1141 fail(); 1142 } catch (WrongMethodTypeException e) {} 1143 try { 1144 assertEquals("[false, true]", mh.invoke(vat, Boolean.valueOf(false), (Boolean) null)); 1145 fail(); 1146 } catch (NullPointerException e) {} 1147 1148 // Methods - byte 1149 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1150 MethodType.methodType(String.class, byte[].class)); 1151 assertTrue(mh.isVarargsCollector()); 1152 assertEquals("[]", mh.invoke(vat)); 1153 assertEquals("[32, 64, 97]", mh.invoke(vat, (byte) 32, Byte.valueOf((byte) 64), (byte) 97)); 1154 assertEquals("[32, 64, 97]", mh.invoke(vat, new byte[] {(byte) 32, (byte) 64, (byte) 97})); 1155 try { 1156 mh.invoke(vat, (byte) 1, Integer.valueOf(3), (byte) 0); 1157 fail(); 1158 } catch (WrongMethodTypeException e) {} 1159 1160 // Methods - char 1161 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1162 MethodType.methodType(String.class, char[].class)); 1163 assertTrue(mh.isVarargsCollector()); 1164 assertEquals("[]", mh.invoke(vat)); 1165 assertEquals("[A, B, C]", mh.invoke(vat, 'A', Character.valueOf('B'), 'C')); 1166 assertEquals("[W, X, Y, Z]", mh.invoke(vat, new char[] { 'W', 'X', 'Y', 'Z' })); 1167 1168 // Methods - short 1169 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1170 MethodType.methodType(String.class, short[].class)); 1171 assertTrue(mh.isVarargsCollector()); 1172 assertEquals("[]", mh.invoke(vat)); 1173 assertEquals("[32767, -32768, 0]", 1174 mh.invoke(vat, Short.MAX_VALUE, Short.MIN_VALUE, Short.valueOf((short) 0))); 1175 assertEquals("[1, -1]", mh.invoke(vat, new short[] { (short) 1, (short) -1 })); 1176 1177 // Methods - int 1178 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1179 MethodType.methodType(String.class, int[].class)); 1180 assertTrue(mh.isVarargsCollector()); 1181 assertEquals("[]", mh.invoke(vat)); 1182 assertEquals("[0, 2147483647, -2147483648, 0]", 1183 mh.invoke(vat, Integer.valueOf(0), Integer.MAX_VALUE, Integer.MIN_VALUE, 0)); 1184 assertEquals("[0, -1, 1, 0]", mh.invoke(vat, new int[] { 0, -1, 1, 0 })); 1185 1186 assertEquals("[5, 4, 3, 2, 1]", (String) mh.invokeExact(vat, new int [] { 5, 4, 3, 2, 1 })); 1187 try { 1188 assertEquals("[5, 4, 3, 2, 1]", (String) mh.invokeExact(vat, 5, 4, 3, 2, 1)); 1189 fail(); 1190 } catch (WrongMethodTypeException e) {} 1191 assertEquals("[5, 4, 3, 2, 1]", (String) mh.invoke(vat, 5, 4, 3, 2, 1)); 1192 1193 // Methods - long 1194 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1195 MethodType.methodType(String.class, long[].class)); 1196 assertTrue(mh.isVarargsCollector()); 1197 assertEquals("[]", mh.invoke(vat)); 1198 assertEquals("[0, 9223372036854775807, -9223372036854775808]", 1199 mh.invoke(vat, Long.valueOf(0), Long.MAX_VALUE, Long.MIN_VALUE)); 1200 assertEquals("[0, -1, 1, 0]", mh.invoke(vat, new long[] { 0, -1, 1, 0 })); 1201 1202 // Methods - float 1203 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1204 MethodType.methodType(String.class, float[].class)); 1205 assertTrue(mh.isVarargsCollector()); 1206 assertEquals("[]", mh.invoke(vat)); 1207 assertEquals("[0.0, 1.25, -1.25]", 1208 mh.invoke(vat, 0.0f, Float.valueOf(1.25f), Float.valueOf(-1.25f))); 1209 assertEquals("[0.0, -1.0, 1.0, 0.0]", 1210 mh.invoke(vat, new float[] { 0.0f, -1.0f, 1.0f, 0.0f })); 1211 1212 // Methods - double 1213 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1214 MethodType.methodType(String.class, double[].class)); 1215 assertTrue(mh.isVarargsCollector()); 1216 assertEquals("[]", mh.invoke(vat)); 1217 assertEquals("[0.0, 1.25, -1.25]", 1218 mh.invoke(vat, 0.0, Double.valueOf(1.25), Double.valueOf(-1.25))); 1219 assertEquals("[0.0, -1.0, 1.0, 0.0]", 1220 mh.invoke(vat, new double[] { 0.0, -1.0, 1.0, 0.0 })); 1221 mh.invoke(vat, 0.3f, 1.33, 1.33); 1222 1223 // Methods - String 1224 mh = MethodHandles.lookup(). 1225 findVirtual(VariableArityTester.class, "update", 1226 MethodType.methodType(String.class, String.class, String[].class)); 1227 assertTrue(mh.isVarargsCollector()); 1228 assertEquals("Echidna, []", mh.invoke(vat, "Echidna")); 1229 assertEquals("Bongo, [Jerboa, Okapi]", 1230 mh.invoke(vat, "Bongo", "Jerboa", "Okapi")); 1231 1232 // Methods - Float 1233 mh = MethodHandles.lookup(). 1234 findVirtual(VariableArityTester.class, "update", 1235 MethodType.methodType(String.class, Float.class, Float[].class)); 1236 assertTrue(mh.isVarargsCollector()); 1237 assertEquals("9.99, [0.0, 0.1, 1.1]", 1238 (String) mh.invoke(vat, Float.valueOf(9.99f), 1239 new Float[] { Float.valueOf(0.0f), 1240 Float.valueOf(0.1f), 1241 Float.valueOf(1.1f) })); 1242 assertEquals("9.99, [0.0, 0.1, 1.1]", 1243 (String) mh.invoke(vat, Float.valueOf(9.99f), Float.valueOf(0.0f), 1244 Float.valueOf(0.1f), Float.valueOf(1.1f))); 1245 assertEquals("9.99, [0.0, 0.1, 1.1]", 1246 (String) mh.invoke(vat, Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f)); 1247 try { 1248 assertEquals("9.99, [77.0, 33.0, 64.0]", 1249 (String) mh.invoke(vat, Float.valueOf(9.99f), 77, 33, 64)); 1250 fail(); 1251 } catch (WrongMethodTypeException e) {} 1252 assertEquals("9.99, [0.0, 0.1, 1.1]", 1253 (String) mh.invokeExact(vat, Float.valueOf(9.99f), 1254 new Float[] { Float.valueOf(0.0f), 1255 Float.valueOf(0.1f), 1256 Float.valueOf(1.1f) })); 1257 assertEquals("9.99, [0.0, null, 1.1]", 1258 (String) mh.invokeExact(vat, Float.valueOf(9.99f), 1259 new Float[] { Float.valueOf(0.0f), 1260 null, 1261 Float.valueOf(1.1f) })); 1262 try { 1263 assertEquals("9.99, [0.0, 0.1, 1.1]", 1264 (String) mh.invokeExact(vat, Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f)); 1265 fail(); 1266 } catch (WrongMethodTypeException e) {} 1267 1268 // Methods - Number 1269 mh = MethodHandles.lookup(). 1270 findVirtual(VariableArityTester.class, "update", 1271 MethodType.methodType(String.class, char.class, Number[].class)); 1272 assertTrue(mh.isVarargsCollector()); 1273 assertFalse(mh.asFixedArity().isVarargsCollector()); 1274 assertEquals("x, []", (String) mh.invoke(vat, 'x')); 1275 assertEquals("x, [3.141]", (String) mh.invoke(vat, 'x', 3.141)); 1276 assertEquals("x, [null, 3.131, 37]", 1277 (String) mh.invoke(vat, 'x', null, 3.131, new Integer(37))); 1278 try { 1279 assertEquals("x, [null, 3.131, bad, 37]", 1280 (String) mh.invoke(vat, 'x', null, 3.131, "bad", new Integer(37))); 1281 assertTrue(false); 1282 fail(); 1283 } catch (ClassCastException e) {} 1284 try { 1285 assertEquals("x, [null, 3.131, bad, 37]", 1286 (String) mh.invoke( 1287 vat, 'x', (Process) null, 3.131, "bad", new Integer(37))); 1288 assertTrue(false); 1289 fail(); 1290 } catch (ClassCastException e) {} 1291 1292 // Methods - an array method that is not variable arity. 1293 mh = MethodHandles.lookup().findVirtual( 1294 VariableArityTester.class, "arrayMethod", 1295 MethodType.methodType(String.class, Object[].class)); 1296 assertFalse(mh.isVarargsCollector()); 1297 mh.invoke(vat, new Object[] { "123" }); 1298 try { 1299 assertEquals("-", mh.invoke(vat, new Float(3), new Float(4))); 1300 fail(); 1301 } catch (WrongMethodTypeException e) {} 1302 mh = mh.asVarargsCollector(Object[].class); 1303 assertTrue(mh.isVarargsCollector()); 1304 assertEquals("[3.0, 4.0]", (String) mh.invoke(vat, new Float(3), new Float(4))); 1305 1306 // Constructors - default 1307 mh = MethodHandles.lookup().findConstructor( 1308 VariableArityTester.class, MethodType.methodType(void.class)); 1309 assertFalse(mh.isVarargsCollector()); 1310 1311 // Constructors - boolean 1312 mh = MethodHandles.lookup().findConstructor( 1313 VariableArityTester.class, MethodType.methodType(void.class, boolean[].class)); 1314 assertTrue(mh.isVarargsCollector()); 1315 assertEquals("[true, true, false]", 1316 ((VariableArityTester) mh.invoke(new boolean[] {true, true, false})).lastResult()); 1317 assertEquals("[true, true, false]", 1318 ((VariableArityTester) mh.invoke(true, true, false)).lastResult()); 1319 try { 1320 assertEquals("[true, true, false]", 1321 ((VariableArityTester) mh.invokeExact(true, true, false)).lastResult()); 1322 fail(); 1323 } catch (WrongMethodTypeException e) {} 1324 1325 // Constructors - byte 1326 mh = MethodHandles.lookup().findConstructor( 1327 VariableArityTester.class, MethodType.methodType(void.class, byte[].class)); 1328 assertTrue(mh.isVarargsCollector()); 1329 assertEquals("[55, 66, 60]", 1330 ((VariableArityTester) 1331 mh.invoke(new byte[] {(byte) 55, (byte) 66, (byte) 60})).lastResult()); 1332 assertEquals("[55, 66, 60]", 1333 ((VariableArityTester) mh.invoke( 1334 (byte) 55, (byte) 66, (byte) 60)).lastResult()); 1335 try { 1336 assertEquals("[55, 66, 60]", 1337 ((VariableArityTester) mh.invokeExact( 1338 (byte) 55, (byte) 66, (byte) 60)).lastResult()); 1339 fail(); 1340 } catch (WrongMethodTypeException e) {} 1341 try { 1342 assertEquals("[3, 3]", 1343 ((VariableArityTester) mh.invoke( 1344 new Number[] { Byte.valueOf((byte) 3), (byte) 3})).lastResult()); 1345 fail(); 1346 } catch (WrongMethodTypeException e) {} 1347 1348 // Constructors - String (have a different path than other reference types). 1349 mh = MethodHandles.lookup().findConstructor( 1350 VariableArityTester.class, MethodType.methodType(void.class, String.class, String[].class)); 1351 assertTrue(mh.isVarargsCollector()); 1352 assertEquals("x, []", ((VariableArityTester) mh.invoke("x")).lastResult()); 1353 assertEquals("x, [y]", ((VariableArityTester) mh.invoke("x", "y")).lastResult()); 1354 assertEquals("x, [y, z]", 1355 ((VariableArityTester) mh.invoke("x", new String[] { "y", "z" })).lastResult()); 1356 try { 1357 assertEquals("x, [y]", ((VariableArityTester) mh.invokeExact("x", "y")).lastResult()); 1358 fail(); 1359 } catch (WrongMethodTypeException e) {} 1360 assertEquals("x, [null, z]", 1361 ((VariableArityTester) mh.invoke("x", new String[] { null, "z" })).lastResult()); 1362 1363 // Constructors - Number 1364 mh = MethodHandles.lookup().findConstructor( 1365 VariableArityTester.class, MethodType.methodType(void.class, char.class, Number[].class)); 1366 assertTrue(mh.isVarargsCollector()); 1367 assertFalse(mh.asFixedArity().isVarargsCollector()); 1368 assertEquals("x, []", ((VariableArityTester) mh.invoke('x')).lastResult()); 1369 assertEquals("x, [3.141]", ((VariableArityTester) mh.invoke('x', 3.141)).lastResult()); 1370 assertEquals("x, [null, 3.131, 37]", 1371 ((VariableArityTester) mh.invoke('x', null, 3.131, new Integer(37))).lastResult()); 1372 try { 1373 assertEquals("x, [null, 3.131, bad, 37]", 1374 ((VariableArityTester) mh.invoke( 1375 'x', null, 3.131, "bad", new Integer(37))).lastResult()); 1376 assertTrue(false); 1377 fail(); 1378 } catch (ClassCastException e) {} 1379 try { 1380 assertEquals("x, [null, 3.131, bad, 37]", 1381 ((VariableArityTester) mh.invoke( 1382 'x', (Process) null, 3.131, "bad", new Integer(37))).lastResult()); 1383 assertTrue(false); 1384 fail(); 1385 } catch (ClassCastException e) {} 1386 1387 // Static Methods - Float 1388 mh = MethodHandles.lookup(). 1389 findStatic(VariableArityTester.class, "tally", 1390 MethodType.methodType(String.class, Float.class, Float[].class)); 1391 assertTrue(mh.isVarargsCollector()); 1392 assertEquals("9.99, [0.0, 0.1, 1.1]", 1393 (String) mh.invoke(Float.valueOf(9.99f), 1394 new Float[] { Float.valueOf(0.0f), 1395 Float.valueOf(0.1f), 1396 Float.valueOf(1.1f) })); 1397 assertEquals("9.99, [0.0, 0.1, 1.1]", 1398 (String) mh.invoke(Float.valueOf(9.99f), Float.valueOf(0.0f), 1399 Float.valueOf(0.1f), Float.valueOf(1.1f))); 1400 assertEquals("9.99, [0.0, 0.1, 1.1]", 1401 (String) mh.invoke(Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f)); 1402 try { 1403 assertEquals("9.99, [77.0, 33.0, 64.0]", 1404 (String) mh.invoke(Float.valueOf(9.99f), 77, 33, 64)); 1405 fail(); 1406 } catch (WrongMethodTypeException e) {} 1407 assertEquals("9.99, [0.0, 0.1, 1.1]", 1408 (String) mh.invokeExact(Float.valueOf(9.99f), 1409 new Float[] { Float.valueOf(0.0f), 1410 Float.valueOf(0.1f), 1411 Float.valueOf(1.1f) })); 1412 assertEquals("9.99, [0.0, null, 1.1]", 1413 (String) mh.invokeExact(Float.valueOf(9.99f), 1414 new Float[] { Float.valueOf(0.0f), 1415 null, 1416 Float.valueOf(1.1f) })); 1417 try { 1418 assertEquals("9.99, [0.0, 0.1, 1.1]", 1419 (String) mh.invokeExact(Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f)); 1420 fail(); 1421 } catch (WrongMethodTypeException e) {} 1422 1423 // Special methods - Float 1424 mh = VariableArityTester.lookup(). 1425 findSpecial(BaseVariableArityTester.class, "update", 1426 MethodType.methodType(String.class, Float.class, Float[].class), 1427 VariableArityTester.class); 1428 assertTrue(mh.isVarargsCollector()); 1429 assertEquals("base 9.99, [0.0, 0.1, 1.1]", 1430 (String) mh.invoke(vat, 1431 Float.valueOf(9.99f), 1432 new Float[] { Float.valueOf(0.0f), 1433 Float.valueOf(0.1f), 1434 Float.valueOf(1.1f) })); 1435 assertEquals("base 9.99, [0.0, 0.1, 1.1]", 1436 (String) mh.invoke(vat, Float.valueOf(9.99f), Float.valueOf(0.0f), 1437 Float.valueOf(0.1f), Float.valueOf(1.1f))); 1438 1439 // Return value conversions. 1440 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1441 MethodType.methodType(String.class, int[].class)); 1442 assertEquals("[1, 2, 3]", (String) mh.invoke(vat, 1, 2, 3)); 1443 assertEquals("[1, 2, 3]", (Object) mh.invoke(vat, 1, 2, 3)); 1444 try { 1445 assertEquals("[1, 2, 3, 4]", (long) mh.invoke(vat, 1, 2, 3)); 1446 fail(); 1447 } catch (WrongMethodTypeException e) {} 1448 assertEquals("[1, 2, 3]", vat.lastResult()); 1449 mh = MethodHandles.lookup().findStatic(VariableArityTester.class, "sumToPrimitive", 1450 MethodType.methodType(long.class, int[].class)); 1451 assertEquals(10l, (long) mh.invoke(1, 2, 3, 4)); 1452 assertEquals(Long.valueOf(10l), (Long) mh.invoke(1, 2, 3, 4)); 1453 mh = MethodHandles.lookup().findStatic(VariableArityTester.class, "sumToReference", 1454 MethodType.methodType(Long.class, int[].class)); 1455 Object o = mh.invoke(1, 2, 3, 4); 1456 long l = (long) mh.invoke(1, 2, 3, 4); 1457 assertEquals(10l, (long) mh.invoke(1, 2, 3, 4)); 1458 assertEquals(Long.valueOf(10l), (Long) mh.invoke(1, 2, 3, 4)); 1459 try { 1460 // WrongMethodTypeException should be raised before invoke here. 1461 System.out.print("Expect Hi here: "); 1462 assertEquals(Long.valueOf(10l), (Byte) mh.invoke(1, 2, 3, 4)); 1463 fail(); 1464 } catch (ClassCastException e) {} 1465 try { 1466 // WrongMethodTypeException should be raised before invoke here. 1467 System.out.println("Don't expect Hi now"); 1468 byte b = (byte) mh.invoke(1, 2, 3, 4); 1469 fail(); 1470 } catch (WrongMethodTypeException e) {} 1471 1472 // Return void produces 0 / null. 1473 mh = MethodHandles.lookup().findStatic(VariableArityTester.class, "foo", 1474 MethodType.methodType(void.class, int[].class)); 1475 assertEquals(null, (Object) mh.invoke(3, 2, 1)); 1476 assertEquals(0l, (long) mh.invoke(1, 2, 3)); 1477 1478 // Combinators 1479 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1480 MethodType.methodType(String.class, boolean[].class)); 1481 assertTrue(mh.isVarargsCollector()); 1482 mh = mh.bindTo(vat); 1483 assertFalse(mh.isVarargsCollector()); 1484 mh = mh.asVarargsCollector(boolean[].class); 1485 assertTrue(mh.isVarargsCollector()); 1486 assertEquals("[]", mh.invoke()); 1487 assertEquals("[true, false, true]", mh.invoke(true, false, true)); 1488 assertEquals("[true, false, true]", mh.invoke(new boolean[] { true, false, true})); 1489 assertEquals("[false, true]", mh.invoke(Boolean.valueOf(false), Boolean.valueOf(true))); 1490 try { 1491 mh.invoke(true, true, 0); 1492 fail(); 1493 } catch (WrongMethodTypeException e) {} 1494 } 1495 1496 // The same tests as the above, except that we use use MethodHandles.bind instead of 1497 // MethodHandle.bindTo. 1498 public static void testVariableArity_MethodHandles_bind() throws Throwable { 1499 VariableArityTester vat = new VariableArityTester(); 1500 MethodHandle mh = MethodHandles.lookup().bind(vat, "update", 1501 MethodType.methodType(String.class, boolean[].class)); 1502 assertTrue(mh.isVarargsCollector()); 1503 1504 assertEquals("[]", mh.invoke()); 1505 assertEquals("[true, false, true]", mh.invoke(true, false, true)); 1506 assertEquals("[true, false, true]", mh.invoke(new boolean[] { true, false, true})); 1507 assertEquals("[false, true]", mh.invoke(Boolean.valueOf(false), Boolean.valueOf(true))); 1508 1509 try { 1510 mh.invoke(true, true, 0); 1511 fail(); 1512 } catch (WrongMethodTypeException e) {} 1513 } 1514 1515 public static void testRevealDirect() throws Throwable { 1516 // Test with a virtual method : 1517 MethodType type = MethodType.methodType(String.class); 1518 MethodHandle handle = MethodHandles.lookup().findVirtual( 1519 UnreflectTester.class, "publicMethod", type); 1520 1521 // Comparisons with an equivalent member obtained via reflection : 1522 MethodHandleInfo info = MethodHandles.lookup().revealDirect(handle); 1523 Method meth = UnreflectTester.class.getMethod("publicMethod"); 1524 1525 assertEquals(MethodHandleInfo.REF_invokeVirtual, info.getReferenceKind()); 1526 assertEquals("publicMethod", info.getName()); 1527 assertTrue(UnreflectTester.class == info.getDeclaringClass()); 1528 assertFalse(info.isVarArgs()); 1529 assertEquals(meth, info.reflectAs(Method.class, MethodHandles.lookup())); 1530 assertEquals(type, info.getMethodType()); 1531 1532 // Resolution via a public lookup should fail because the method in question 1533 // isn't public. 1534 try { 1535 info.reflectAs(Method.class, MethodHandles.publicLookup()); 1536 fail(); 1537 } catch (IllegalArgumentException expected) { 1538 } 1539 1540 // Test with a static method : 1541 handle = MethodHandles.lookup().findStatic(UnreflectTester.class, 1542 "publicStaticMethod", 1543 MethodType.methodType(String.class)); 1544 1545 info = MethodHandles.lookup().revealDirect(handle); 1546 meth = UnreflectTester.class.getMethod("publicStaticMethod"); 1547 assertEquals(MethodHandleInfo.REF_invokeStatic, info.getReferenceKind()); 1548 assertEquals("publicStaticMethod", info.getName()); 1549 assertTrue(UnreflectTester.class == info.getDeclaringClass()); 1550 assertFalse(info.isVarArgs()); 1551 assertEquals(meth, info.reflectAs(Method.class, MethodHandles.lookup())); 1552 assertEquals(type, info.getMethodType()); 1553 1554 // Test with a var-args method : 1555 type = MethodType.methodType(String.class, String[].class); 1556 handle = MethodHandles.lookup().findVirtual(UnreflectTester.class, 1557 "publicVarArgsMethod", type); 1558 1559 info = MethodHandles.lookup().revealDirect(handle); 1560 meth = UnreflectTester.class.getMethod("publicVarArgsMethod", String[].class); 1561 assertEquals(MethodHandleInfo.REF_invokeVirtual, info.getReferenceKind()); 1562 assertEquals("publicVarArgsMethod", info.getName()); 1563 assertTrue(UnreflectTester.class == info.getDeclaringClass()); 1564 assertTrue(info.isVarArgs()); 1565 assertEquals(meth, info.reflectAs(Method.class, MethodHandles.lookup())); 1566 assertEquals(type, info.getMethodType()); 1567 1568 // Test with a constructor : 1569 Constructor cons = UnreflectTester.class.getConstructor(String.class, boolean.class); 1570 type = MethodType.methodType(void.class, String.class, boolean.class); 1571 handle = MethodHandles.lookup().findConstructor(UnreflectTester.class, type); 1572 1573 info = MethodHandles.lookup().revealDirect(handle); 1574 assertEquals(MethodHandleInfo.REF_newInvokeSpecial, info.getReferenceKind()); 1575 assertEquals("<init>", info.getName()); 1576 assertTrue(UnreflectTester.class == info.getDeclaringClass()); 1577 assertFalse(info.isVarArgs()); 1578 assertEquals(cons, info.reflectAs(Constructor.class, MethodHandles.lookup())); 1579 assertEquals(type, info.getMethodType()); 1580 1581 // Test with a static field : 1582 Field field = UnreflectTester.class.getField("publicStaticField"); 1583 1584 handle = MethodHandles.lookup().findStaticSetter( 1585 UnreflectTester.class, "publicStaticField", String.class); 1586 1587 info = MethodHandles.lookup().revealDirect(handle); 1588 assertEquals(MethodHandleInfo.REF_putStatic, info.getReferenceKind()); 1589 assertEquals("publicStaticField", info.getName()); 1590 assertTrue(UnreflectTester.class == info.getDeclaringClass()); 1591 assertFalse(info.isVarArgs()); 1592 assertEquals(field, info.reflectAs(Field.class, MethodHandles.lookup())); 1593 assertEquals(MethodType.methodType(void.class, String.class), info.getMethodType()); 1594 1595 // Test with a setter on the same field, the type of the handle should change 1596 // but everything else must remain the same. 1597 handle = MethodHandles.lookup().findStaticGetter( 1598 UnreflectTester.class, "publicStaticField", String.class); 1599 info = MethodHandles.lookup().revealDirect(handle); 1600 assertEquals(MethodHandleInfo.REF_getStatic, info.getReferenceKind()); 1601 assertEquals(field, info.reflectAs(Field.class, MethodHandles.lookup())); 1602 assertEquals(MethodType.methodType(String.class), info.getMethodType()); 1603 1604 // Test with an instance field : 1605 field = UnreflectTester.class.getField("publicField"); 1606 1607 handle = MethodHandles.lookup().findSetter( 1608 UnreflectTester.class, "publicField", String.class); 1609 1610 info = MethodHandles.lookup().revealDirect(handle); 1611 assertEquals(MethodHandleInfo.REF_putField, info.getReferenceKind()); 1612 assertEquals("publicField", info.getName()); 1613 assertTrue(UnreflectTester.class == info.getDeclaringClass()); 1614 assertFalse(info.isVarArgs()); 1615 assertEquals(field, info.reflectAs(Field.class, MethodHandles.lookup())); 1616 assertEquals(MethodType.methodType(void.class, String.class), info.getMethodType()); 1617 1618 // Test with a setter on the same field, the type of the handle should change 1619 // but everything else must remain the same. 1620 handle = MethodHandles.lookup().findGetter( 1621 UnreflectTester.class, "publicField", String.class); 1622 info = MethodHandles.lookup().revealDirect(handle); 1623 assertEquals(MethodHandleInfo.REF_getField, info.getReferenceKind()); 1624 assertEquals(field, info.reflectAs(Field.class, MethodHandles.lookup())); 1625 assertEquals(MethodType.methodType(String.class), info.getMethodType()); 1626 } 1627 } 1628