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 assertTrue(boolean value)669 public static void assertTrue(boolean value) { 670 if (!value) { 671 throw new AssertionError("assertTrue value: " + value); 672 } 673 } 674 assertFalse(boolean value)675 public static void assertFalse(boolean value) { 676 if (value) { 677 throw new AssertionError("assertTrue value: " + value); 678 } 679 } 680 assertEquals(int i1, int i2)681 public static void assertEquals(int i1, int i2) { 682 if (i1 == i2) { return; } 683 throw new AssertionError("assertEquals i1: " + i1 + ", i2: " + i2); 684 } 685 assertEquals(long i1, long i2)686 public static void assertEquals(long i1, long i2) { 687 if (i1 == i2) { return; } 688 throw new AssertionError("assertEquals l1: " + i1 + ", l2: " + i2); 689 } 690 assertEquals(Object o, Object p)691 public static void assertEquals(Object o, Object p) { 692 if (o == p) { return; } 693 if (o != null && p != null && o.equals(p)) { return; } 694 throw new AssertionError("assertEquals: o1: " + o + ", o2: " + p); 695 } 696 assertEquals(String s1, String s2)697 public static void assertEquals(String s1, String s2) { 698 if (s1 == s2) { 699 return; 700 } 701 702 if (s1 != null && s2 != null && s1.equals(s2)) { 703 return; 704 } 705 706 throw new AssertionError("assertEquals s1: " + s1 + ", s2: " + s2); 707 } 708 fail()709 public static void fail() { 710 System.out.println("fail"); 711 Thread.dumpStack(); 712 } 713 fail(String message)714 public static void fail(String message) { 715 System.out.println("fail: " + message); 716 Thread.dumpStack(); 717 } 718 testConstructors()719 public static void testConstructors() throws Throwable { 720 MethodHandle mh = 721 MethodHandles.lookup().findConstructor(Float.class, 722 MethodType.methodType(void.class, 723 float.class)); 724 Float value = (Float) mh.invokeExact(0.33f); 725 if (value.floatValue() != 0.33f) { 726 fail("Unexpected float value from invokeExact " + value.floatValue()); 727 } 728 729 value = (Float) mh.invoke(3.34f); 730 if (value.floatValue() != 3.34f) { 731 fail("Unexpected float value from invoke " + value.floatValue()); 732 } 733 734 mh = MethodHandles.lookup().findConstructor(Double.class, 735 MethodType.methodType(void.class, String.class)); 736 Double d = (Double) mh.invoke("8.45e3"); 737 if (d.doubleValue() != 8.45e3) { 738 fail("Unexpected double value from Double(String) " + value.doubleValue()); 739 } 740 741 mh = MethodHandles.lookup().findConstructor(Double.class, 742 MethodType.methodType(void.class, double.class)); 743 d = (Double) mh.invoke(8.45e3); 744 if (d.doubleValue() != 8.45e3) { 745 fail("Unexpected double value from Double(double) " + value.doubleValue()); 746 } 747 748 // Primitive type 749 try { 750 mh = MethodHandles.lookup().findConstructor(int.class, MethodType.methodType(void.class)); 751 fail("Unexpected lookup success for primitive constructor"); 752 } catch (NoSuchMethodException e) {} 753 754 // Interface 755 try { 756 mh = MethodHandles.lookup().findConstructor(Readable.class, 757 MethodType.methodType(void.class)); 758 fail("Unexpected lookup success for interface constructor"); 759 } catch (NoSuchMethodException e) {} 760 761 // Abstract 762 mh = MethodHandles.lookup().findConstructor(Process.class, MethodType.methodType(void.class)); 763 try { 764 mh.invoke(); 765 fail("Unexpected ability to instantiate an abstract class"); 766 } catch (InstantiationException e) {} 767 768 // Non-existent 769 try { 770 MethodHandle bad = MethodHandles.lookup().findConstructor( 771 String.class, MethodType.methodType(String.class, Float.class)); 772 fail("Unexpected success for non-existent constructor"); 773 } catch (NoSuchMethodException e) {} 774 775 // Non-void constructor search. (I)I instead of (I)V. 776 try { 777 MethodHandle foo = MethodHandles.lookup().findConstructor( 778 Integer.class, MethodType.methodType(Integer.class, Integer.class)); 779 fail("Unexpected success for non-void type for findConstructor"); 780 } catch (NoSuchMethodException e) {} 781 782 // Array class constructor. 783 try { 784 MethodHandle foo = MethodHandles.lookup().findConstructor( 785 Object[].class, MethodType.methodType(void.class)); 786 fail("Unexpected success for array class type for findConstructor"); 787 } catch (NoSuchMethodException e) {} 788 789 // Child class constructor (b/143343351) 790 { 791 MethodHandle handle = MethodHandles.lookup().findConstructor( 792 ArrayList.class, MethodType.methodType(void.class)); 793 AbstractList list = (AbstractList) handle.asType(MethodType.methodType(AbstractList.class)) 794 .invokeExact(); 795 } 796 } 797 testStringConstructors()798 public static void testStringConstructors() throws Throwable { 799 final String testPattern = "The system as we know it is broken"; 800 801 // String() 802 MethodHandle mh = MethodHandles.lookup().findConstructor( 803 String.class, MethodType.methodType(void.class)); 804 String s = (String) mh.invokeExact(); 805 if (!s.equals("")) { 806 fail("Unexpected empty string constructor result: '" + s + "'"); 807 } 808 809 // String(String) 810 mh = MethodHandles.lookup().findConstructor( 811 String.class, MethodType.methodType(void.class, String.class)); 812 s = (String) mh.invokeExact(testPattern); 813 if (!s.equals(testPattern)) { 814 fail("Unexpected string constructor result: '" + s + "'"); 815 } 816 817 // String(char[]) 818 mh = MethodHandles.lookup().findConstructor( 819 String.class, MethodType.methodType(void.class, char[].class)); 820 s = (String) mh.invokeExact(testPattern.toCharArray()); 821 if (!s.equals(testPattern)) { 822 fail("Unexpected string constructor result: '" + s + "'"); 823 } 824 825 // String(char[], int, int) 826 mh = MethodHandles.lookup().findConstructor( 827 String.class, MethodType.methodType(void.class, char[].class, int.class, int.class)); 828 s = (String) mh.invokeExact(new char [] { 'a', 'b', 'c', 'd', 'e'}, 2, 3); 829 if (!s.equals("cde")) { 830 fail("Unexpected string constructor result: '" + s + "'"); 831 } 832 833 // String(int[] codePoints, int offset, int count) 834 StringBuffer sb = new StringBuffer(testPattern); 835 int[] codePoints = new int[sb.codePointCount(0, sb.length())]; 836 for (int i = 0; i < sb.length(); ++i) { 837 codePoints[i] = sb.codePointAt(i); 838 } 839 mh = MethodHandles.lookup().findConstructor( 840 String.class, MethodType.methodType(void.class, int[].class, int.class, int.class)); 841 s = (String) mh.invokeExact(codePoints, 0, codePoints.length); 842 if (!s.equals(testPattern)) { 843 fail("Unexpected string constructor result: '" + s + "'"); 844 } 845 846 // String(byte ascii[], int hibyte, int offset, int count) 847 byte [] ascii = testPattern.getBytes(StandardCharsets.US_ASCII); 848 mh = MethodHandles.lookup().findConstructor( 849 String.class, MethodType.methodType(void.class, byte[].class, int.class, int.class)); 850 s = (String) mh.invokeExact(ascii, 0, ascii.length); 851 if (!s.equals(testPattern)) { 852 fail("Unexpected string constructor result: '" + s + "'"); 853 } 854 855 // String(byte bytes[], int offset, int length, String charsetName) 856 mh = MethodHandles.lookup().findConstructor( 857 String.class, 858 MethodType.methodType(void.class, byte[].class, int.class, int.class, String.class)); 859 s = (String) mh.invokeExact(ascii, 0, 5, StandardCharsets.US_ASCII.name()); 860 if (!s.equals(testPattern.substring(0, 5))) { 861 fail("Unexpected string constructor result: '" + s + "'"); 862 } 863 864 // String(byte bytes[], int offset, int length, Charset charset) 865 mh = MethodHandles.lookup().findConstructor( 866 String.class, 867 MethodType.methodType(void.class, byte[].class, int.class, int.class, Charset.class)); 868 s = (String) mh.invokeExact(ascii, 0, 5, StandardCharsets.US_ASCII); 869 if (!s.equals(testPattern.substring(0, 5))) { 870 fail("Unexpected string constructor result: '" + s + "'"); 871 } 872 873 // String(byte bytes[], String charsetName) 874 mh = MethodHandles.lookup().findConstructor( 875 String.class, 876 MethodType.methodType(void.class, byte[].class, String.class)); 877 s = (String) mh.invokeExact(ascii, StandardCharsets.US_ASCII.name()); 878 if (!s.equals(testPattern)) { 879 fail("Unexpected string constructor result: '" + s + "'"); 880 } 881 882 // String(byte bytes[], Charset charset) 883 mh = MethodHandles.lookup().findConstructor( 884 String.class, MethodType.methodType(void.class, byte[].class, Charset.class)); 885 s = (String) mh.invokeExact(ascii, StandardCharsets.US_ASCII); 886 if (!s.equals(testPattern)) { 887 fail("Unexpected string constructor result: '" + s + "'"); 888 } 889 890 // String(byte bytes[], int offset, int length) 891 mh = MethodHandles.lookup().findConstructor( 892 String.class, MethodType.methodType(void.class, byte[].class, int.class, int.class)); 893 s = (String) mh.invokeExact(ascii, 1, ascii.length - 2); 894 s = testPattern.charAt(0) + s + testPattern.charAt(testPattern.length() - 1); 895 if (!s.equals(testPattern)) { 896 fail("Unexpected string constructor result: '" + s + "'"); 897 } 898 899 // String(byte bytes[]) 900 mh = MethodHandles.lookup().findConstructor( 901 String.class, MethodType.methodType(void.class, byte[].class)); 902 s = (String) mh.invokeExact(ascii); 903 if (!s.equals(testPattern)) { 904 fail("Unexpected string constructor result: '" + s + "'"); 905 } 906 907 // String(StringBuffer buffer) 908 mh = MethodHandles.lookup().findConstructor( 909 String.class, MethodType.methodType(void.class, StringBuffer.class)); 910 s = (String) mh.invokeExact(sb); 911 if (!s.equals(testPattern)) { 912 fail("Unexpected string constructor result: '" + s + "'"); 913 } 914 915 // Child class constructor (b/143343351) 916 { 917 MethodHandle handle = MethodHandles.lookup().findConstructor( 918 String.class, MethodType.methodType(void.class)); 919 CharSequence o = (CharSequence) handle.asType(MethodType.methodType(CharSequence.class)) 920 .invokeExact(); 921 if (!o.equals("")) { 922 fail("Unexpected child class constructor result: '" + o + "'"); 923 } 924 } 925 System.out.println("String constructors done."); 926 } 927 testReturnValues()928 private static void testReturnValues() throws Throwable { 929 Lookup lookup = MethodHandles.lookup(); 930 931 // byte 932 MethodHandle mhByteValue = 933 lookup.findVirtual(Byte.class, "byteValue", MethodType.methodType(byte.class)); 934 assertEquals((byte) -77, (byte) mhByteValue.invokeExact(Byte.valueOf((byte) -77))); 935 assertEquals((byte) -77, (byte) mhByteValue.invoke(Byte.valueOf((byte) -77))); 936 937 // char 938 MethodHandle mhCharacterValue = 939 lookup.findStaticGetter(Character.class, "MAX_SURROGATE", char.class); 940 assertEquals(Character.MAX_SURROGATE, (char) mhCharacterValue.invokeExact()); 941 assertEquals(Character.MAX_SURROGATE, (char) mhCharacterValue.invoke()); 942 943 // double 944 MethodHandle mhSin = 945 lookup.findStatic( 946 Math.class, "sin", MethodType.methodType(double.class, double.class)); 947 for (double i = -Math.PI; i <= Math.PI; i += Math.PI / 8) { 948 assertEquals(Math.sin(i), (double) mhSin.invokeExact(i)); 949 assertEquals(Math.sin(i), (double) mhSin.invoke(i)); 950 } 951 952 // float 953 MethodHandle mhAbsFloat = 954 lookup.findStatic( 955 Math.class, "abs", MethodType.methodType(float.class, float.class)); 956 assertEquals(Math.abs(-3.3e6f), (float) mhAbsFloat.invokeExact(-3.3e6f)); 957 assertEquals(Math.abs(-3.3e6f), (float) mhAbsFloat.invoke(-3.3e6f)); 958 959 // int 960 MethodHandle mhAbsInt = 961 lookup.findStatic(Math.class, "abs", MethodType.methodType(int.class, int.class)); 962 assertEquals(Math.abs(-1000), (int) mhAbsInt.invokeExact(-1000)); 963 assertEquals(Math.abs(-1000), (int) mhAbsInt.invoke(-1000)); 964 965 // long 966 MethodHandle mhMaxLong = 967 lookup.findStatic( 968 Math.class, 969 "max", 970 MethodType.methodType(long.class, long.class, long.class)); 971 assertEquals( 972 Long.MAX_VALUE, (long) mhMaxLong.invokeExact(Long.MAX_VALUE, Long.MAX_VALUE / 2)); 973 assertEquals(Long.MAX_VALUE, (long) mhMaxLong.invoke(Long.MAX_VALUE, Long.MAX_VALUE / 2)); 974 assertEquals(0x0123456789abcdefL, (long) mhMaxLong.invokeExact(0x0123456789abcdefL, 0L)); 975 assertEquals(0x0123456789abcdefL, (long) mhMaxLong.invoke(0x0123456789abcdefL, 0L)); 976 977 // ref 978 MethodHandle mhShortValueOf = 979 lookup.findStatic( 980 Short.class, "valueOf", MethodType.methodType(Short.class, short.class)); 981 assertEquals( 982 (short) -7890, ((Short) mhShortValueOf.invokeExact((short) -7890)).shortValue()); 983 assertEquals((short) -7890, ((Short) mhShortValueOf.invoke((short) -7890)).shortValue()); 984 985 // array 986 int [] array = {Integer.MIN_VALUE, -1, 0, +1, Integer.MAX_VALUE}; 987 MethodHandle mhCopyOf = 988 lookup.findStatic( 989 Arrays.class, "copyOf", MethodType.methodType(int[].class, int[].class, int.class)); 990 assertTrue(Arrays.equals(array, (int[]) mhCopyOf.invokeExact(array, array.length))); 991 assertTrue(Arrays.equals(array, (int[]) mhCopyOf.invoke(array, array.length))); 992 993 // short 994 MethodHandle mhShortValue = 995 lookup.findVirtual(Short.class, "shortValue", MethodType.methodType(short.class)); 996 assertEquals((short) 12131, (short) mhShortValue.invokeExact(Short.valueOf((short) 12131))); 997 assertEquals((short) 12131, (short) mhShortValue.invoke(Short.valueOf((short) 12131))); 998 999 // boolean 1000 MethodHandle mhBooleanValue = 1001 lookup.findVirtual( 1002 Boolean.class, "booleanValue", MethodType.methodType(boolean.class)); 1003 assertEquals(true, (boolean) mhBooleanValue.invokeExact(Boolean.valueOf(true))); 1004 assertEquals(true, (boolean) mhBooleanValue.invoke(Boolean.valueOf(true))); 1005 assertEquals(false, (boolean) mhBooleanValue.invokeExact(Boolean.valueOf(false))); 1006 assertEquals(false, (boolean) mhBooleanValue.invoke(Boolean.valueOf(false))); 1007 1008 System.out.println("testReturnValues done."); 1009 } 1010 testReferenceReturnValueConversions()1011 private static void testReferenceReturnValueConversions() throws Throwable { 1012 MethodHandle mh = MethodHandles.lookup().findStatic( 1013 Float.class, "valueOf", MethodType.methodType(Float.class, String.class)); 1014 1015 // No conversion 1016 Float f = (Float) mh.invokeExact("1.375"); 1017 if (f.floatValue() != 1.375) { 1018 fail(); 1019 } 1020 f = (Float) mh.invoke("1.875"); 1021 if (f.floatValue() != 1.875) { 1022 fail(); 1023 } 1024 1025 // Bad conversion 1026 try { 1027 int i = (int) mh.invokeExact("7.77"); 1028 fail(); 1029 } catch (WrongMethodTypeException e) {} 1030 1031 try { 1032 int i = (int) mh.invoke("7.77"); 1033 fail(); 1034 } catch (WrongMethodTypeException e) {} 1035 1036 // Assignment to super-class. 1037 Number n = (Number) mh.invoke("1.11"); 1038 try { 1039 Number o = (Number) mh.invokeExact("1.11"); 1040 fail(); 1041 } catch (WrongMethodTypeException e) {} 1042 1043 // Assignment to widened boxed primitive class. 1044 try { 1045 Double u = (Double) mh.invoke("1.11"); 1046 fail(); 1047 } catch (ClassCastException e) {} 1048 1049 try { 1050 Double v = (Double) mh.invokeExact("1.11"); 1051 fail(); 1052 } catch (WrongMethodTypeException e) {} 1053 1054 // Unboxed 1055 float p = (float) mh.invoke("1.11"); 1056 if (p != 1.11f) { 1057 fail(); 1058 } 1059 1060 // Unboxed and widened 1061 double d = (double) mh.invoke("2.5"); 1062 if (d != 2.5) { 1063 fail(); 1064 } 1065 1066 // Interface 1067 Comparable<Float> c = (Comparable<Float>) mh.invoke("2.125"); 1068 if (c.compareTo(new Float(2.125f)) != 0) { 1069 fail(); 1070 } 1071 1072 System.out.println("testReferenceReturnValueConversions done."); 1073 } 1074 testPrimitiveReturnValueConversions()1075 private static void testPrimitiveReturnValueConversions() throws Throwable { 1076 MethodHandle mh = MethodHandles.lookup().findStatic( 1077 Math.class, "min", MethodType.methodType(int.class, int.class, int.class)); 1078 1079 final int SMALL = -8972; 1080 final int LARGE = 7932529; 1081 1082 // No conversion 1083 if ((int) mh.invokeExact(LARGE, SMALL) != SMALL) { 1084 fail(); 1085 } else if ((int) mh.invoke(LARGE, SMALL) != SMALL) { 1086 fail(); 1087 } else if ((int) mh.invokeExact(SMALL, LARGE) != SMALL) { 1088 fail(); 1089 } else if ((int) mh.invoke(SMALL, LARGE) != SMALL) { 1090 fail(); 1091 } 1092 1093 // int -> long 1094 try { 1095 if ((long) mh.invokeExact(LARGE, SMALL) != (long) SMALL) {} 1096 fail(); 1097 } catch (WrongMethodTypeException e) {} 1098 1099 if ((long) mh.invoke(LARGE, SMALL) != (long) SMALL) { 1100 fail(); 1101 } 1102 1103 // int -> short 1104 try { 1105 if ((short) mh.invokeExact(LARGE, SMALL) != (short) SMALL) {} 1106 fail(); 1107 } catch (WrongMethodTypeException e) {} 1108 1109 try { 1110 if ((short) mh.invoke(LARGE, SMALL) != (short) SMALL) { 1111 fail(); 1112 } 1113 } catch (WrongMethodTypeException e) {} 1114 1115 // int -> Integer 1116 try { 1117 if (!((Integer) mh.invokeExact(LARGE, SMALL)).equals(new Integer(SMALL))) {} 1118 fail(); 1119 } catch (WrongMethodTypeException e) {} 1120 1121 if (!((Integer) mh.invoke(LARGE, SMALL)).equals(new Integer(SMALL))) { 1122 fail(); 1123 } 1124 1125 // int -> Long 1126 try { 1127 Long l = (Long) mh.invokeExact(LARGE, SMALL); 1128 fail(); 1129 } catch (WrongMethodTypeException e) {} 1130 1131 try { 1132 Long l = (Long) mh.invoke(LARGE, SMALL); 1133 fail(); 1134 } catch (WrongMethodTypeException e) {} 1135 1136 // int -> Short 1137 try { 1138 Short s = (Short) mh.invokeExact(LARGE, SMALL); 1139 fail(); 1140 } catch (WrongMethodTypeException e) {} 1141 1142 try { 1143 Short s = (Short) mh.invoke(LARGE, SMALL); 1144 fail(); 1145 } catch (WrongMethodTypeException e) {} 1146 1147 // int -> Process 1148 try { 1149 Process p = (Process) mh.invokeExact(LARGE, SMALL); 1150 fail(); 1151 } catch (WrongMethodTypeException e) {} 1152 1153 try { 1154 Process p = (Process) mh.invoke(LARGE, SMALL); 1155 fail(); 1156 } catch (WrongMethodTypeException e) {} 1157 1158 // void -> Object 1159 mh = MethodHandles.lookup().findStatic(System.class, "gc", MethodType.methodType(void.class)); 1160 Object o = (Object) mh.invoke(); 1161 if (o != null) fail(); 1162 1163 // void -> long 1164 long l = (long) mh.invoke(); 1165 if (l != 0) fail(); 1166 1167 // boolean -> Boolean 1168 mh = MethodHandles.lookup().findStatic(Boolean.class, "parseBoolean", 1169 MethodType.methodType(boolean.class, String.class)); 1170 Boolean z = (Boolean) mh.invoke("True"); 1171 if (!z.booleanValue()) fail(); 1172 1173 // boolean -> int 1174 try { 1175 int unexpectedValue = (int) mh.invoke("True"); 1176 fail(); 1177 } catch (WrongMethodTypeException e) {} 1178 1179 // boolean -> Integer 1180 try { 1181 Integer unexpectedValue = (Integer) mh.invoke("True"); 1182 fail(); 1183 } catch (WrongMethodTypeException e) {} 1184 1185 // Boolean -> boolean 1186 mh = MethodHandles.lookup().findStatic(Boolean.class, "valueOf", 1187 MethodType.methodType(Boolean.class, boolean.class)); 1188 boolean w = (boolean) mh.invoke(false); 1189 if (w) fail(); 1190 1191 // Boolean -> int 1192 try { 1193 int unexpectedValue = (int) mh.invoke(false); 1194 fail(); 1195 } catch (WrongMethodTypeException e) {} 1196 1197 // Boolean -> Integer 1198 try { 1199 Integer unexpectedValue = (Integer) mh.invoke("True"); 1200 fail(); 1201 } catch (WrongMethodTypeException e) {} 1202 1203 System.out.println("testPrimitiveReturnValueConversions done."); 1204 } 1205 testReturnValueConversions()1206 public static void testReturnValueConversions() throws Throwable { 1207 testReferenceReturnValueConversions(); 1208 testPrimitiveReturnValueConversions(); 1209 } 1210 1211 public static class BaseVariableArityTester { update(Float f0, Float... floats)1212 public String update(Float f0, Float... floats) { 1213 return "base " + f0 + ", " + Arrays.toString(floats); 1214 } 1215 } 1216 1217 public static class VariableArityTester extends BaseVariableArityTester { 1218 private String lastResult; 1219 1220 // Constructors VariableArityTester()1221 public VariableArityTester() {} VariableArityTester(boolean... booleans)1222 public VariableArityTester(boolean... booleans) { update(booleans); } VariableArityTester(byte... bytes)1223 public VariableArityTester(byte... bytes) { update(bytes); } VariableArityTester(char... chars)1224 public VariableArityTester(char... chars) { update(chars); } VariableArityTester(short... shorts)1225 public VariableArityTester(short... shorts) { update(shorts); } VariableArityTester(int... ints)1226 public VariableArityTester(int... ints) { update(ints); } VariableArityTester(long... longs)1227 public VariableArityTester(long... longs) { update(longs); } VariableArityTester(float... floats)1228 public VariableArityTester(float... floats) { update(floats); } VariableArityTester(double... doubles)1229 public VariableArityTester(double... doubles) { update(doubles); } VariableArityTester(Float f0, Float... floats)1230 public VariableArityTester(Float f0, Float... floats) { update(f0, floats); } VariableArityTester(String s0, String... strings)1231 public VariableArityTester(String s0, String... strings) { update(s0, strings); } VariableArityTester(char c, Number... numbers)1232 public VariableArityTester(char c, Number... numbers) { update(c, numbers); } 1233 @SafeVarargs VariableArityTester(ArrayList<Integer> l0, ArrayList<Integer>... lists)1234 public VariableArityTester(ArrayList<Integer> l0, ArrayList<Integer>... lists) { 1235 update(l0, lists); 1236 } VariableArityTester(List l0, List... lists)1237 public VariableArityTester(List l0, List... lists) { update(l0, lists); } 1238 1239 // Methods update(boolean... booleans)1240 public String update(boolean... booleans) { return lastResult = tally(booleans); } update(byte... bytes)1241 public String update(byte... bytes) { return lastResult = tally(bytes); } update(char... chars)1242 public String update(char... chars) { return lastResult = tally(chars); } update(short... shorts)1243 public String update(short... shorts) { return lastResult = tally(shorts); } update(int... ints)1244 public String update(int... ints) { 1245 lastResult = tally(ints); 1246 return lastResult; 1247 } update(long... longs)1248 public String update(long... longs) { return lastResult = tally(longs); } update(float... floats)1249 public String update(float... floats) { return lastResult = tally(floats); } update(double... doubles)1250 public String update(double... doubles) { return lastResult = tally(doubles); } 1251 @Override update(Float f0, Float... floats)1252 public String update(Float f0, Float... floats) { return lastResult = tally(f0, floats); } update(String s0, String... strings)1253 public String update(String s0, String... strings) { return lastResult = tally(s0, strings); } update(char c, Number... numbers)1254 public String update(char c, Number... numbers) { return lastResult = tally(c, numbers); } 1255 @SafeVarargs update(ArrayList<Integer> l0, ArrayList<Integer>... lists)1256 public final String update(ArrayList<Integer> l0, ArrayList<Integer>... lists) { 1257 lastResult = tally(l0, lists); 1258 return lastResult; 1259 } update(List l0, List... lists)1260 public String update(List l0, List... lists) { return lastResult = tally(l0, lists); } 1261 arrayMethod(Object[] o)1262 public String arrayMethod(Object[] o) { 1263 return Arrays.deepToString(o); 1264 } 1265 lastResult()1266 public String lastResult() { return lastResult; } 1267 1268 // Static Methods tally(boolean... booleans)1269 public static String tally(boolean... booleans) { return Arrays.toString(booleans); } tally(byte... bytes)1270 public static String tally(byte... bytes) { return Arrays.toString(bytes); } tally(char... chars)1271 public static String tally(char... chars) { return Arrays.toString(chars); } tally(short... shorts)1272 public static String tally(short... shorts) { return Arrays.toString(shorts); } tally(int... ints)1273 public static String tally(int... ints) { return Arrays.toString(ints); } tally(long... longs)1274 public static String tally(long... longs) { return Arrays.toString(longs); } tally(float... floats)1275 public static String tally(float... floats) { return Arrays.toString(floats); } tally(double... doubles)1276 public static String tally(double... doubles) { return Arrays.toString(doubles); } tally(Float f0, Float... floats)1277 public static String tally(Float f0, Float... floats) { 1278 return f0 + ", " + Arrays.toString(floats); 1279 } tally(String s0, String... strings)1280 public static String tally(String s0, String... strings) { 1281 return s0 + ", " + Arrays.toString(strings); 1282 } tally(char c, Number... numbers)1283 public static String tally(char c, Number... numbers) { 1284 return c + ", " + Arrays.toString(numbers); 1285 } 1286 @SafeVarargs tally(ArrayList<Integer> l0, ArrayList<Integer>... lists)1287 public static String tally(ArrayList<Integer> l0, ArrayList<Integer>... lists) { 1288 return Arrays.toString(l0.toArray()) + ", " + Arrays.deepToString(lists); 1289 } tally(List l0, List... lists)1290 public static String tally(List l0, List... lists) { 1291 return Arrays.deepToString(l0.toArray()) + ", " + Arrays.deepToString(lists); 1292 } foo(int... ints)1293 public static void foo(int... ints) { System.out.println(Arrays.toString(ints)); } sumToPrimitive(int... ints)1294 public static long sumToPrimitive(int... ints) { 1295 long result = 0; 1296 for (int i : ints) result += i; 1297 return result; 1298 } sumToReference(int... ints)1299 public static Long sumToReference(int... ints) { 1300 System.out.println("Hi"); 1301 return new Long(sumToPrimitive(ints)); 1302 } lookup()1303 public static MethodHandles.Lookup lookup() { 1304 return MethodHandles.lookup(); 1305 } 1306 } 1307 1308 // This method only exists to fool Jack's handling of types. See b/32536744. getAsObject(String[] strings)1309 public static Object getAsObject(String[] strings) { 1310 return (Object) strings; 1311 } 1312 testVariableArity()1313 public static void testVariableArity() throws Throwable { 1314 MethodHandle mh; 1315 VariableArityTester vat = new VariableArityTester(); 1316 1317 assertEquals("[1]", vat.update(1)); 1318 assertEquals("[1, 1]", vat.update(1, 1)); 1319 assertEquals("[1, 1, 1]", vat.update(1, 1, 1)); 1320 1321 // Methods - boolean 1322 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1323 MethodType.methodType(String.class, boolean[].class)); 1324 assertTrue(mh.isVarargsCollector()); 1325 assertFalse(mh.asFixedArity().isVarargsCollector()); 1326 assertEquals("[]", mh.invoke(vat)); 1327 assertEquals("[true, false, true]", mh.invoke(vat, true, false, true)); 1328 assertEquals("[true, false, true]", mh.invoke(vat, new boolean[] { true, false, true})); 1329 assertEquals("[false, true]", mh.invoke(vat, Boolean.valueOf(false), Boolean.valueOf(true))); 1330 try { 1331 mh.invoke(vat, true, true, 0); 1332 fail(); 1333 } catch (WrongMethodTypeException e) {} 1334 try { 1335 assertEquals("[false, true]", mh.invoke(vat, Boolean.valueOf(false), (Boolean) null)); 1336 fail(); 1337 } catch (NullPointerException e) {} 1338 1339 // Methods - byte 1340 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1341 MethodType.methodType(String.class, byte[].class)); 1342 assertTrue(mh.isVarargsCollector()); 1343 assertEquals("[]", mh.invoke(vat)); 1344 assertEquals("[32, 64, 97]", mh.invoke(vat, (byte) 32, Byte.valueOf((byte) 64), (byte) 97)); 1345 assertEquals("[32, 64, 97]", mh.invoke(vat, new byte[] {(byte) 32, (byte) 64, (byte) 97})); 1346 try { 1347 mh.invoke(vat, (byte) 1, Integer.valueOf(3), (byte) 0); 1348 fail(); 1349 } catch (WrongMethodTypeException e) {} 1350 1351 // Methods - char 1352 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1353 MethodType.methodType(String.class, char[].class)); 1354 assertTrue(mh.isVarargsCollector()); 1355 assertEquals("[]", mh.invoke(vat)); 1356 assertEquals("[A, B, C]", mh.invoke(vat, 'A', Character.valueOf('B'), 'C')); 1357 assertEquals("[W, X, Y, Z]", mh.invoke(vat, new char[] { 'W', 'X', 'Y', 'Z' })); 1358 1359 // Methods - short 1360 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1361 MethodType.methodType(String.class, short[].class)); 1362 assertTrue(mh.isVarargsCollector()); 1363 assertEquals("[]", mh.invoke(vat)); 1364 assertEquals("[32767, -32768, 0]", 1365 mh.invoke(vat, Short.MAX_VALUE, Short.MIN_VALUE, Short.valueOf((short) 0))); 1366 assertEquals("[1, -1]", mh.invoke(vat, new short[] { (short) 1, (short) -1 })); 1367 1368 // Methods - int 1369 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1370 MethodType.methodType(String.class, int[].class)); 1371 assertTrue(mh.isVarargsCollector()); 1372 assertEquals("[]", mh.invoke(vat)); 1373 assertEquals("[0, 2147483647, -2147483648, 0]", 1374 mh.invoke(vat, Integer.valueOf(0), Integer.MAX_VALUE, Integer.MIN_VALUE, 0)); 1375 assertEquals("[0, -1, 1, 0]", mh.invoke(vat, new int[] { 0, -1, 1, 0 })); 1376 1377 assertEquals("[5, 4, 3, 2, 1]", (String) mh.invokeExact(vat, new int [] { 5, 4, 3, 2, 1 })); 1378 try { 1379 assertEquals("[5, 4, 3, 2, 1]", (String) mh.invokeExact(vat, 5, 4, 3, 2, 1)); 1380 fail(); 1381 } catch (WrongMethodTypeException e) {} 1382 assertEquals("[5, 4, 3, 2, 1]", (String) mh.invoke(vat, 5, 4, 3, 2, 1)); 1383 1384 // Methods - long 1385 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1386 MethodType.methodType(String.class, long[].class)); 1387 assertTrue(mh.isVarargsCollector()); 1388 assertEquals("[]", mh.invoke(vat)); 1389 assertEquals("[0, 9223372036854775807, -9223372036854775808]", 1390 mh.invoke(vat, Long.valueOf(0), Long.MAX_VALUE, Long.MIN_VALUE)); 1391 assertEquals("[0, -1, 1, 0]", mh.invoke(vat, new long[] { 0, -1, 1, 0 })); 1392 1393 // Methods - float 1394 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1395 MethodType.methodType(String.class, float[].class)); 1396 assertTrue(mh.isVarargsCollector()); 1397 assertEquals("[]", mh.invoke(vat)); 1398 assertEquals("[0.0, 1.25, -1.25]", 1399 mh.invoke(vat, 0.0f, Float.valueOf(1.25f), Float.valueOf(-1.25f))); 1400 assertEquals("[0.0, -1.0, 1.0, 0.0]", 1401 mh.invoke(vat, new float[] { 0.0f, -1.0f, 1.0f, 0.0f })); 1402 1403 // Methods - double 1404 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1405 MethodType.methodType(String.class, double[].class)); 1406 assertTrue(mh.isVarargsCollector()); 1407 assertEquals("[]", mh.invoke(vat)); 1408 assertEquals("[0.0, 1.25, -1.25]", 1409 mh.invoke(vat, 0.0, Double.valueOf(1.25), Double.valueOf(-1.25))); 1410 assertEquals("[0.0, -1.0, 1.0, 0.0]", 1411 mh.invoke(vat, new double[] { 0.0, -1.0, 1.0, 0.0 })); 1412 mh.invoke(vat, 0.3f, 1.33, 1.33); 1413 1414 // Methods - String 1415 mh = MethodHandles.lookup(). 1416 findVirtual(VariableArityTester.class, "update", 1417 MethodType.methodType(String.class, String.class, String[].class)); 1418 assertTrue(mh.isVarargsCollector()); 1419 assertEquals("Echidna, []", mh.invoke(vat, "Echidna")); 1420 assertEquals("Bongo, [Jerboa, Okapi]", 1421 mh.invoke(vat, "Bongo", "Jerboa", "Okapi")); 1422 1423 // Methods - Float 1424 mh = MethodHandles.lookup(). 1425 findVirtual(VariableArityTester.class, "update", 1426 MethodType.methodType(String.class, Float.class, Float[].class)); 1427 assertTrue(mh.isVarargsCollector()); 1428 assertEquals("9.99, [0.0, 0.1, 1.1]", 1429 (String) mh.invoke(vat, Float.valueOf(9.99f), 1430 new Float[] { Float.valueOf(0.0f), 1431 Float.valueOf(0.1f), 1432 Float.valueOf(1.1f) })); 1433 assertEquals("9.99, [0.0, 0.1, 1.1]", 1434 (String) mh.invoke(vat, Float.valueOf(9.99f), Float.valueOf(0.0f), 1435 Float.valueOf(0.1f), Float.valueOf(1.1f))); 1436 assertEquals("9.99, [0.0, 0.1, 1.1]", 1437 (String) mh.invoke(vat, Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f)); 1438 try { 1439 assertEquals("9.99, [77.0, 33.0, 64.0]", 1440 (String) mh.invoke(vat, Float.valueOf(9.99f), 77, 33, 64)); 1441 fail(); 1442 } catch (WrongMethodTypeException e) {} 1443 assertEquals("9.99, [0.0, 0.1, 1.1]", 1444 (String) mh.invokeExact(vat, Float.valueOf(9.99f), 1445 new Float[] { Float.valueOf(0.0f), 1446 Float.valueOf(0.1f), 1447 Float.valueOf(1.1f) })); 1448 assertEquals("9.99, [0.0, null, 1.1]", 1449 (String) mh.invokeExact(vat, Float.valueOf(9.99f), 1450 new Float[] { Float.valueOf(0.0f), 1451 null, 1452 Float.valueOf(1.1f) })); 1453 try { 1454 assertEquals("9.99, [0.0, 0.1, 1.1]", 1455 (String) mh.invokeExact(vat, Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f)); 1456 fail(); 1457 } catch (WrongMethodTypeException e) {} 1458 1459 // Methods - Number 1460 mh = MethodHandles.lookup(). 1461 findVirtual(VariableArityTester.class, "update", 1462 MethodType.methodType(String.class, char.class, Number[].class)); 1463 assertTrue(mh.isVarargsCollector()); 1464 assertFalse(mh.asFixedArity().isVarargsCollector()); 1465 assertEquals("x, []", (String) mh.invoke(vat, 'x')); 1466 assertEquals("x, [3.141]", (String) mh.invoke(vat, 'x', 3.141)); 1467 assertEquals("x, [null, 3.131, 37]", 1468 (String) mh.invoke(vat, 'x', null, 3.131, new Integer(37))); 1469 try { 1470 assertEquals("x, [null, 3.131, bad, 37]", 1471 (String) mh.invoke(vat, 'x', null, 3.131, "bad", new Integer(37))); 1472 assertTrue(false); 1473 fail(); 1474 } catch (ClassCastException e) {} 1475 try { 1476 assertEquals("x, [null, 3.131, bad, 37]", 1477 (String) mh.invoke( 1478 vat, 'x', (Process) null, 3.131, "bad", new Integer(37))); 1479 assertTrue(false); 1480 fail(); 1481 } catch (ClassCastException e) {} 1482 1483 // Methods - an array method that is not variable arity. 1484 mh = MethodHandles.lookup().findVirtual( 1485 VariableArityTester.class, "arrayMethod", 1486 MethodType.methodType(String.class, Object[].class)); 1487 assertFalse(mh.isVarargsCollector()); 1488 mh.invoke(vat, new Object[] { "123" }); 1489 try { 1490 assertEquals("-", mh.invoke(vat, new Float(3), new Float(4))); 1491 fail(); 1492 } catch (WrongMethodTypeException e) {} 1493 mh = mh.asVarargsCollector(Object[].class); 1494 assertTrue(mh.isVarargsCollector()); 1495 assertEquals("[3.0, 4.0]", (String) mh.invoke(vat, new Float(3), new Float(4))); 1496 1497 // Constructors - default 1498 mh = MethodHandles.lookup().findConstructor( 1499 VariableArityTester.class, MethodType.methodType(void.class)); 1500 assertFalse(mh.isVarargsCollector()); 1501 1502 // Constructors - boolean 1503 mh = MethodHandles.lookup().findConstructor( 1504 VariableArityTester.class, MethodType.methodType(void.class, boolean[].class)); 1505 assertTrue(mh.isVarargsCollector()); 1506 assertEquals("[true, true, false]", 1507 ((VariableArityTester) mh.invoke(new boolean[] {true, true, false})).lastResult()); 1508 assertEquals("[true, true, false]", 1509 ((VariableArityTester) mh.invoke(true, true, false)).lastResult()); 1510 try { 1511 assertEquals("[true, true, false]", 1512 ((VariableArityTester) mh.invokeExact(true, true, false)).lastResult()); 1513 fail(); 1514 } catch (WrongMethodTypeException e) {} 1515 1516 // Constructors - byte 1517 mh = MethodHandles.lookup().findConstructor( 1518 VariableArityTester.class, MethodType.methodType(void.class, byte[].class)); 1519 assertTrue(mh.isVarargsCollector()); 1520 assertEquals("[55, 66, 60]", 1521 ((VariableArityTester) 1522 mh.invoke(new byte[] {(byte) 55, (byte) 66, (byte) 60})).lastResult()); 1523 assertEquals("[55, 66, 60]", 1524 ((VariableArityTester) mh.invoke( 1525 (byte) 55, (byte) 66, (byte) 60)).lastResult()); 1526 try { 1527 assertEquals("[55, 66, 60]", 1528 ((VariableArityTester) mh.invokeExact( 1529 (byte) 55, (byte) 66, (byte) 60)).lastResult()); 1530 fail(); 1531 } catch (WrongMethodTypeException e) {} 1532 try { 1533 assertEquals("[3, 3]", 1534 ((VariableArityTester) mh.invoke( 1535 new Number[] { Byte.valueOf((byte) 3), (byte) 3})).lastResult()); 1536 fail(); 1537 } catch (WrongMethodTypeException e) {} 1538 1539 // Constructors - String (have a different path than other reference types). 1540 mh = MethodHandles.lookup().findConstructor( 1541 VariableArityTester.class, MethodType.methodType(void.class, String.class, String[].class)); 1542 assertTrue(mh.isVarargsCollector()); 1543 assertEquals("x, []", ((VariableArityTester) mh.invoke("x")).lastResult()); 1544 assertEquals("x, [y]", ((VariableArityTester) mh.invoke("x", "y")).lastResult()); 1545 assertEquals("x, [y, z]", 1546 ((VariableArityTester) mh.invoke("x", new String[] { "y", "z" })).lastResult()); 1547 try { 1548 assertEquals("x, [y]", ((VariableArityTester) mh.invokeExact("x", "y")).lastResult()); 1549 fail(); 1550 } catch (WrongMethodTypeException e) {} 1551 assertEquals("x, [null, z]", 1552 ((VariableArityTester) mh.invoke("x", new String[] { null, "z" })).lastResult()); 1553 1554 // Constructors - Number 1555 mh = MethodHandles.lookup().findConstructor( 1556 VariableArityTester.class, MethodType.methodType(void.class, char.class, Number[].class)); 1557 assertTrue(mh.isVarargsCollector()); 1558 assertFalse(mh.asFixedArity().isVarargsCollector()); 1559 assertEquals("x, []", ((VariableArityTester) mh.invoke('x')).lastResult()); 1560 assertEquals("x, [3.141]", ((VariableArityTester) mh.invoke('x', 3.141)).lastResult()); 1561 assertEquals("x, [null, 3.131, 37]", 1562 ((VariableArityTester) mh.invoke('x', null, 3.131, new Integer(37))).lastResult()); 1563 try { 1564 assertEquals("x, [null, 3.131, bad, 37]", 1565 ((VariableArityTester) mh.invoke( 1566 'x', null, 3.131, "bad", new Integer(37))).lastResult()); 1567 assertTrue(false); 1568 fail(); 1569 } catch (ClassCastException e) {} 1570 try { 1571 assertEquals("x, [null, 3.131, bad, 37]", 1572 ((VariableArityTester) mh.invoke( 1573 'x', (Process) null, 3.131, "bad", new Integer(37))).lastResult()); 1574 assertTrue(false); 1575 fail(); 1576 } catch (ClassCastException e) {} 1577 1578 // Static Methods - Float 1579 mh = MethodHandles.lookup(). 1580 findStatic(VariableArityTester.class, "tally", 1581 MethodType.methodType(String.class, Float.class, Float[].class)); 1582 assertTrue(mh.isVarargsCollector()); 1583 assertEquals("9.99, [0.0, 0.1, 1.1]", 1584 (String) mh.invoke(Float.valueOf(9.99f), 1585 new Float[] { Float.valueOf(0.0f), 1586 Float.valueOf(0.1f), 1587 Float.valueOf(1.1f) })); 1588 assertEquals("9.99, [0.0, 0.1, 1.1]", 1589 (String) mh.invoke(Float.valueOf(9.99f), Float.valueOf(0.0f), 1590 Float.valueOf(0.1f), Float.valueOf(1.1f))); 1591 assertEquals("9.99, [0.0, 0.1, 1.1]", 1592 (String) mh.invoke(Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f)); 1593 try { 1594 assertEquals("9.99, [77.0, 33.0, 64.0]", 1595 (String) mh.invoke(Float.valueOf(9.99f), 77, 33, 64)); 1596 fail(); 1597 } catch (WrongMethodTypeException e) {} 1598 assertEquals("9.99, [0.0, 0.1, 1.1]", 1599 (String) mh.invokeExact(Float.valueOf(9.99f), 1600 new Float[] { Float.valueOf(0.0f), 1601 Float.valueOf(0.1f), 1602 Float.valueOf(1.1f) })); 1603 assertEquals("9.99, [0.0, null, 1.1]", 1604 (String) mh.invokeExact(Float.valueOf(9.99f), 1605 new Float[] { Float.valueOf(0.0f), 1606 null, 1607 Float.valueOf(1.1f) })); 1608 try { 1609 assertEquals("9.99, [0.0, 0.1, 1.1]", 1610 (String) mh.invokeExact(Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f)); 1611 fail(); 1612 } catch (WrongMethodTypeException e) {} 1613 1614 // Special methods - Float 1615 mh = VariableArityTester.lookup(). 1616 findSpecial(BaseVariableArityTester.class, "update", 1617 MethodType.methodType(String.class, Float.class, Float[].class), 1618 VariableArityTester.class); 1619 assertTrue(mh.isVarargsCollector()); 1620 assertEquals("base 9.99, [0.0, 0.1, 1.1]", 1621 (String) mh.invoke(vat, 1622 Float.valueOf(9.99f), 1623 new Float[] { Float.valueOf(0.0f), 1624 Float.valueOf(0.1f), 1625 Float.valueOf(1.1f) })); 1626 assertEquals("base 9.99, [0.0, 0.1, 1.1]", 1627 (String) mh.invoke(vat, Float.valueOf(9.99f), Float.valueOf(0.0f), 1628 Float.valueOf(0.1f), Float.valueOf(1.1f))); 1629 1630 // Return value conversions. 1631 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1632 MethodType.methodType(String.class, int[].class)); 1633 assertEquals("[1, 2, 3]", (String) mh.invoke(vat, 1, 2, 3)); 1634 assertEquals("[1, 2, 3]", (Object) mh.invoke(vat, 1, 2, 3)); 1635 try { 1636 assertEquals("[1, 2, 3, 4]", (long) mh.invoke(vat, 1, 2, 3)); 1637 fail(); 1638 } catch (WrongMethodTypeException e) {} 1639 assertEquals("[1, 2, 3]", vat.lastResult()); 1640 mh = MethodHandles.lookup().findStatic(VariableArityTester.class, "sumToPrimitive", 1641 MethodType.methodType(long.class, int[].class)); 1642 assertEquals(10l, (long) mh.invoke(1, 2, 3, 4)); 1643 assertEquals(Long.valueOf(10l), (Long) mh.invoke(1, 2, 3, 4)); 1644 mh = MethodHandles.lookup().findStatic(VariableArityTester.class, "sumToReference", 1645 MethodType.methodType(Long.class, int[].class)); 1646 Object o = mh.invoke(1, 2, 3, 4); 1647 long l = (long) mh.invoke(1, 2, 3, 4); 1648 assertEquals(10l, (long) mh.invoke(1, 2, 3, 4)); 1649 assertEquals(Long.valueOf(10l), (Long) mh.invoke(1, 2, 3, 4)); 1650 try { 1651 // WrongMethodTypeException should be raised before invoke here. 1652 System.out.print("Expect Hi here: "); 1653 assertEquals(Long.valueOf(10l), (Byte) mh.invoke(1, 2, 3, 4)); 1654 fail(); 1655 } catch (ClassCastException e) {} 1656 try { 1657 // WrongMethodTypeException should be raised before invoke here. 1658 System.out.println("Don't expect Hi now"); 1659 byte b = (byte) mh.invoke(1, 2, 3, 4); 1660 fail(); 1661 } catch (WrongMethodTypeException e) {} 1662 1663 // Return void produces 0 / null. 1664 mh = MethodHandles.lookup().findStatic(VariableArityTester.class, "foo", 1665 MethodType.methodType(void.class, int[].class)); 1666 assertEquals(null, (Object) mh.invoke(3, 2, 1)); 1667 assertEquals(0l, (long) mh.invoke(1, 2, 3)); 1668 1669 // Combinators 1670 mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update", 1671 MethodType.methodType(String.class, boolean[].class)); 1672 assertTrue(mh.isVarargsCollector()); 1673 mh = mh.bindTo(vat); 1674 assertFalse(mh.isVarargsCollector()); 1675 mh = mh.asVarargsCollector(boolean[].class); 1676 assertTrue(mh.isVarargsCollector()); 1677 assertEquals("[]", mh.invoke()); 1678 assertEquals("[true, false, true]", mh.invoke(true, false, true)); 1679 assertEquals("[true, false, true]", mh.invoke(new boolean[] { true, false, true})); 1680 assertEquals("[false, true]", mh.invoke(Boolean.valueOf(false), Boolean.valueOf(true))); 1681 try { 1682 mh.invoke(true, true, 0); 1683 fail(); 1684 } catch (WrongMethodTypeException e) {} 1685 } 1686 1687 // The same tests as the above, except that we use use MethodHandles.bind instead of 1688 // MethodHandle.bindTo. testVariableArity_MethodHandles_bind()1689 public static void testVariableArity_MethodHandles_bind() throws Throwable { 1690 VariableArityTester vat = new VariableArityTester(); 1691 MethodHandle mh = MethodHandles.lookup().bind(vat, "update", 1692 MethodType.methodType(String.class, boolean[].class)); 1693 assertTrue(mh.isVarargsCollector()); 1694 1695 assertEquals("[]", mh.invoke()); 1696 assertEquals("[true, false, true]", mh.invoke(true, false, true)); 1697 assertEquals("[true, false, true]", mh.invoke(new boolean[] { true, false, true})); 1698 assertEquals("[false, true]", mh.invoke(Boolean.valueOf(false), Boolean.valueOf(true))); 1699 1700 try { 1701 mh.invoke(true, true, 0); 1702 fail(); 1703 } catch (WrongMethodTypeException e) {} 1704 } 1705 testRevealDirect()1706 public static void testRevealDirect() throws Throwable { 1707 // Test with a virtual method : 1708 MethodType type = MethodType.methodType(String.class); 1709 MethodHandle handle = MethodHandles.lookup().findVirtual( 1710 UnreflectTester.class, "publicMethod", type); 1711 1712 // Comparisons with an equivalent member obtained via reflection : 1713 MethodHandleInfo info = MethodHandles.lookup().revealDirect(handle); 1714 Method meth = UnreflectTester.class.getMethod("publicMethod"); 1715 1716 assertEquals(MethodHandleInfo.REF_invokeVirtual, info.getReferenceKind()); 1717 assertEquals("publicMethod", info.getName()); 1718 assertTrue(UnreflectTester.class == info.getDeclaringClass()); 1719 assertFalse(info.isVarArgs()); 1720 assertEquals(meth, info.reflectAs(Method.class, MethodHandles.lookup())); 1721 assertEquals(type, info.getMethodType()); 1722 1723 // Resolution via a public lookup should fail because the method in question 1724 // isn't public. 1725 try { 1726 info.reflectAs(Method.class, MethodHandles.publicLookup()); 1727 fail(); 1728 } catch (IllegalArgumentException expected) { 1729 } 1730 1731 // Test with a static method : 1732 handle = MethodHandles.lookup().findStatic(UnreflectTester.class, 1733 "publicStaticMethod", 1734 MethodType.methodType(String.class)); 1735 1736 info = MethodHandles.lookup().revealDirect(handle); 1737 meth = UnreflectTester.class.getMethod("publicStaticMethod"); 1738 assertEquals(MethodHandleInfo.REF_invokeStatic, info.getReferenceKind()); 1739 assertEquals("publicStaticMethod", 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 // Test with a var-args method : 1746 type = MethodType.methodType(String.class, String[].class); 1747 handle = MethodHandles.lookup().findVirtual(UnreflectTester.class, 1748 "publicVarArgsMethod", type); 1749 1750 info = MethodHandles.lookup().revealDirect(handle); 1751 meth = UnreflectTester.class.getMethod("publicVarArgsMethod", String[].class); 1752 assertEquals(MethodHandleInfo.REF_invokeVirtual, info.getReferenceKind()); 1753 assertEquals("publicVarArgsMethod", info.getName()); 1754 assertTrue(UnreflectTester.class == info.getDeclaringClass()); 1755 assertTrue(info.isVarArgs()); 1756 assertEquals(meth, info.reflectAs(Method.class, MethodHandles.lookup())); 1757 assertEquals(type, info.getMethodType()); 1758 1759 // Test with a constructor : 1760 Constructor cons = UnreflectTester.class.getConstructor(String.class, boolean.class); 1761 type = MethodType.methodType(void.class, String.class, boolean.class); 1762 handle = MethodHandles.lookup().findConstructor(UnreflectTester.class, type); 1763 1764 info = MethodHandles.lookup().revealDirect(handle); 1765 assertEquals(MethodHandleInfo.REF_newInvokeSpecial, info.getReferenceKind()); 1766 assertEquals("<init>", info.getName()); 1767 assertTrue(UnreflectTester.class == info.getDeclaringClass()); 1768 assertFalse(info.isVarArgs()); 1769 assertEquals(cons, info.reflectAs(Constructor.class, MethodHandles.lookup())); 1770 assertEquals(type, info.getMethodType()); 1771 1772 // Test with a static field : 1773 Field field = UnreflectTester.class.getField("publicStaticField"); 1774 1775 handle = MethodHandles.lookup().findStaticSetter( 1776 UnreflectTester.class, "publicStaticField", String.class); 1777 1778 info = MethodHandles.lookup().revealDirect(handle); 1779 assertEquals(MethodHandleInfo.REF_putStatic, info.getReferenceKind()); 1780 assertEquals("publicStaticField", info.getName()); 1781 assertTrue(UnreflectTester.class == info.getDeclaringClass()); 1782 assertFalse(info.isVarArgs()); 1783 assertEquals(field, info.reflectAs(Field.class, MethodHandles.lookup())); 1784 assertEquals(MethodType.methodType(void.class, String.class), info.getMethodType()); 1785 1786 // Test with a setter on the same field, the type of the handle should change 1787 // but everything else must remain the same. 1788 handle = MethodHandles.lookup().findStaticGetter( 1789 UnreflectTester.class, "publicStaticField", String.class); 1790 info = MethodHandles.lookup().revealDirect(handle); 1791 assertEquals(MethodHandleInfo.REF_getStatic, info.getReferenceKind()); 1792 assertEquals(field, info.reflectAs(Field.class, MethodHandles.lookup())); 1793 assertEquals(MethodType.methodType(String.class), info.getMethodType()); 1794 1795 // Test with an instance field : 1796 field = UnreflectTester.class.getField("publicField"); 1797 1798 handle = MethodHandles.lookup().findSetter( 1799 UnreflectTester.class, "publicField", String.class); 1800 1801 info = MethodHandles.lookup().revealDirect(handle); 1802 assertEquals(MethodHandleInfo.REF_putField, info.getReferenceKind()); 1803 assertEquals("publicField", info.getName()); 1804 assertTrue(UnreflectTester.class == info.getDeclaringClass()); 1805 assertFalse(info.isVarArgs()); 1806 assertEquals(field, info.reflectAs(Field.class, MethodHandles.lookup())); 1807 assertEquals(MethodType.methodType(void.class, String.class), info.getMethodType()); 1808 1809 // Test with a setter on the same field, the type of the handle should change 1810 // but everything else must remain the same. 1811 handle = MethodHandles.lookup().findGetter( 1812 UnreflectTester.class, "publicField", String.class); 1813 info = MethodHandles.lookup().revealDirect(handle); 1814 assertEquals(MethodHandleInfo.REF_getField, info.getReferenceKind()); 1815 assertEquals(field, info.reflectAs(Field.class, MethodHandles.lookup())); 1816 assertEquals(MethodType.methodType(String.class), info.getMethodType()); 1817 } 1818 testReflectiveCalls()1819 public static void testReflectiveCalls() throws Throwable { 1820 String[] methodNames = { "invoke", "invokeExact" }; 1821 for (String methodName : methodNames) { 1822 Method invokeMethod = MethodHandle.class.getMethod(methodName, Object[].class); 1823 MethodHandle instance = 1824 MethodHandles.lookup().findVirtual(java.io.PrintStream.class, "println", 1825 MethodType.methodType(void.class, String.class)); 1826 try { 1827 invokeMethod.invoke(instance, new Object[] { new Object[] { Integer.valueOf(1) } } ); 1828 fail(); 1829 } catch (InvocationTargetException ite) { 1830 assertEquals(ite.getCause().getClass(), UnsupportedOperationException.class); 1831 } 1832 } 1833 } 1834 testInterfaceSpecial()1835 public static void testInterfaceSpecial() throws Throwable { 1836 final Method acceptMethod = Consumer.class.getDeclaredMethod("accept", Object.class); 1837 final Method andThenMethod = Consumer.class.getDeclaredMethod("andThen", Consumer.class); 1838 // Proxies 1839 Consumer<Object> c = (Consumer<Object>)Proxy.newProxyInstance( 1840 Main.class.getClassLoader(), 1841 new Class<?>[] { Consumer.class }, 1842 (p, m, a) -> { 1843 System.out.println("Trying to call " + m); 1844 if (m.equals(andThenMethod)) { 1845 List<Object> args = a == null ? Collections.EMPTY_LIST : Arrays.asList(a); 1846 return MethodHandles.lookup() 1847 .findSpecial(Consumer.class, 1848 m.getName(), 1849 MethodType.methodType(m.getReturnType(), 1850 m.getParameterTypes()), 1851 p.getClass()) 1852 .bindTo(p) 1853 .invokeWithArguments(args); 1854 } else if (m.equals(acceptMethod)) { 1855 System.out.println("Called accept with " + a[0]); 1856 } 1857 return null; 1858 }); 1859 c.accept("foo"); 1860 Consumer<Object> c2 = c.andThen((Object o) -> { System.out.println("and then " + o); }); 1861 c2.accept("bar"); 1862 1863 // Non-proxies 1864 Consumer<Object> c3 = new Consumer() { 1865 public void accept(Object o) { 1866 System.out.println("Got " + o); 1867 } 1868 @Override 1869 public Consumer<Object> andThen(Consumer c) { 1870 System.out.println("Ignoring and then"); 1871 return this; 1872 } 1873 }; 1874 Consumer<Object> c4 = c3.andThen((x) -> { throw new Error("Failed"); }); 1875 c4.accept("hello"); 1876 Consumer<Object> andthen = (Object o) -> { System.out.println("Called and then with " + o);}; 1877 Consumer<Object> c5 = 1878 (Consumer<Object>)MethodHandles.lookup() 1879 .findSpecial(Consumer.class, 1880 andThenMethod.getName(), 1881 MethodType.methodType( 1882 andThenMethod.getReturnType(), 1883 andThenMethod.getParameterTypes()), 1884 c3.getClass()) 1885 .bindTo(c3) 1886 .invoke(andthen); 1887 c5.accept("hello there"); 1888 1889 // Failures 1890 MethodHandle abstract_target = 1891 MethodHandles.lookup() 1892 .findSpecial(Consumer.class, 1893 acceptMethod.getName(), 1894 MethodType.methodType(acceptMethod.getReturnType(), 1895 acceptMethod.getParameterTypes()), 1896 c3.getClass()); 1897 try { 1898 abstract_target.invoke(c3, "hello"); 1899 } catch (IllegalAccessException e) { 1900 System.out.println("Got expected IAE when invoke-special on an abstract interface method"); 1901 } 1902 } 1903 } 1904