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