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