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