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