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