• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
A()35     public A() {}
36 
foo()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 {
foo()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 {
privateRyan()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 
main(String[] args)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 
testfindSpecial_invokeSuperBehaviour()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 
testfindSpecial_invokeDirectBehaviour()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 
testExceptionDetailMessages()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 {
foo()179     public String foo();
180   }
181 
182   public interface Bar extends Foo {
bar()183     public String bar();
184   }
185 
186   public static abstract class BarAbstractSuper {
abstractSuperPublicMethod()187     public abstract String abstractSuperPublicMethod();
188   }
189 
190   public static class BarSuper extends BarAbstractSuper {
superPublicMethod()191     public String superPublicMethod() {
192       return "superPublicMethod";
193     }
194 
superProtectedMethod()195     protected String superProtectedMethod() {
196       return "superProtectedMethod";
197     }
198 
abstractSuperPublicMethod()199     public String abstractSuperPublicMethod() {
200       return "abstractSuperPublicMethod";
201     }
202 
superPackageMethod()203     String superPackageMethod() {
204       return "superPackageMethod";
205     }
206   }
207 
208   public static class BarImpl extends BarSuper implements Bar {
BarImpl()209     public BarImpl() {
210     }
211 
212     @Override
foo()213     public String foo() {
214       return "foo";
215     }
216 
217     @Override
bar()218     public String bar() {
219       return "bar";
220     }
221 
add(int x, int y)222     public String add(int x, int y) {
223       return Arrays.toString(new int[] { x, y });
224     }
225 
privateMethod()226     private String privateMethod() { return "privateMethod"; }
227 
staticMethod()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 
testfindVirtual()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 
testfindStatic()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 
UnreflectTester(String val)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.
UnreflectTester(String val, boolean unused)382     public UnreflectTester(String val, boolean unused) {
383       this(val);
384     }
385 
privateStaticMethod()386     private static String privateStaticMethod() {
387       return "privateStaticMethod";
388     }
389 
privateMethod()390     private String privateMethod() {
391       return "privateMethod";
392     }
393 
publicStaticMethod()394     public static String publicStaticMethod() {
395       return "publicStaticMethod";
396     }
397 
publicMethod()398     public String publicMethod() {
399       return "publicMethod";
400     }
401 
publicVarArgsMethod(String... args)402     public String publicVarArgsMethod(String... args) {
403       return "publicVarArgsMethod";
404     }
405   }
406 
testUnreflects()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.
getSequence()532   public static CharSequence getSequence() {
533     return "foo";
534   }
535 
testAsType()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 
assertTrue(boolean value)579   public static void assertTrue(boolean value) {
580     if (!value) {
581       throw new AssertionError("assertTrue value: " + value);
582     }
583   }
584 
assertFalse(boolean value)585   public static void assertFalse(boolean value) {
586     if (value) {
587       throw new AssertionError("assertTrue value: " + value);
588     }
589   }
590 
assertEquals(int i1, int i2)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 
assertEquals(long i1, long i2)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 
assertEquals(Object o, Object p)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 
assertEquals(String s1, String s2)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 
fail()619   public static void fail() {
620     System.out.println("fail");
621     Thread.dumpStack();
622   }
623 
fail(String message)624   public static void fail(String message) {
625     System.out.println("fail: " + message);
626     Thread.dumpStack();
627   }
628 
testConstructors()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 
testStringConstructors()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 
testReferenceReturnValueConversions()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 
testPrimitiveReturnValueConversions()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 
testReturnValueConversions()1015   public static void testReturnValueConversions() throws Throwable {
1016     testReferenceReturnValueConversions();
1017     testPrimitiveReturnValueConversions();
1018   }
1019 
1020   public static class BaseVariableArityTester {
update(Float f0, Float... floats)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
VariableArityTester()1030     public VariableArityTester() {}
VariableArityTester(boolean... booleans)1031     public VariableArityTester(boolean... booleans) { update(booleans); }
VariableArityTester(byte... bytes)1032     public VariableArityTester(byte... bytes) { update(bytes); }
VariableArityTester(char... chars)1033     public VariableArityTester(char... chars) { update(chars); }
VariableArityTester(short... shorts)1034     public VariableArityTester(short... shorts) { update(shorts); }
VariableArityTester(int... ints)1035     public VariableArityTester(int... ints) { update(ints); }
VariableArityTester(long... longs)1036     public VariableArityTester(long... longs) { update(longs); }
VariableArityTester(float... floats)1037     public VariableArityTester(float... floats) { update(floats); }
VariableArityTester(double... doubles)1038     public VariableArityTester(double... doubles) { update(doubles); }
VariableArityTester(Float f0, Float... floats)1039     public VariableArityTester(Float f0, Float... floats) { update(f0, floats); }
VariableArityTester(String s0, String... strings)1040     public VariableArityTester(String s0, String... strings) { update(s0, strings); }
VariableArityTester(char c, Number... numbers)1041     public VariableArityTester(char c, Number... numbers) { update(c, numbers); }
1042     @SafeVarargs
VariableArityTester(ArrayList<Integer> l0, ArrayList<Integer>... lists)1043     public VariableArityTester(ArrayList<Integer> l0, ArrayList<Integer>... lists) {
1044       update(l0, lists);
1045     }
VariableArityTester(List l0, List... lists)1046     public VariableArityTester(List l0, List... lists) { update(l0, lists); }
1047 
1048     // Methods
update(boolean... booleans)1049     public String update(boolean... booleans) { return lastResult = tally(booleans); }
update(byte... bytes)1050     public String update(byte... bytes) { return lastResult = tally(bytes); }
update(char... chars)1051     public String update(char... chars) { return lastResult = tally(chars); }
update(short... shorts)1052     public String update(short... shorts) { return lastResult = tally(shorts); }
update(int... ints)1053     public String update(int... ints) {
1054       lastResult = tally(ints);
1055       return lastResult;
1056     }
update(long... longs)1057     public String update(long... longs) { return lastResult = tally(longs); }
update(float... floats)1058     public String update(float... floats) { return lastResult = tally(floats); }
update(double... doubles)1059     public String update(double... doubles) { return lastResult = tally(doubles); }
1060     @Override
update(Float f0, Float... floats)1061     public String update(Float f0, Float... floats) { return lastResult = tally(f0, floats); }
update(String s0, String... strings)1062     public String update(String s0, String... strings) { return lastResult = tally(s0, strings); }
update(char c, Number... numbers)1063     public String update(char c, Number... numbers) { return lastResult = tally(c, numbers); }
1064     @SafeVarargs
update(ArrayList<Integer> l0, ArrayList<Integer>... lists)1065     public final String update(ArrayList<Integer> l0, ArrayList<Integer>... lists) {
1066       lastResult = tally(l0, lists);
1067       return lastResult;
1068     }
update(List l0, List... lists)1069     public String update(List l0, List... lists) { return lastResult = tally(l0, lists); }
1070 
arrayMethod(Object[] o)1071     public String arrayMethod(Object[] o) {
1072       return Arrays.deepToString(o);
1073     }
1074 
lastResult()1075     public String lastResult() { return lastResult; }
1076 
1077     // Static Methods
tally(boolean... booleans)1078     public static String tally(boolean... booleans) { return Arrays.toString(booleans); }
tally(byte... bytes)1079     public static String tally(byte... bytes) { return Arrays.toString(bytes); }
tally(char... chars)1080     public static String tally(char... chars) { return Arrays.toString(chars); }
tally(short... shorts)1081     public static String tally(short... shorts) { return Arrays.toString(shorts); }
tally(int... ints)1082     public static String tally(int... ints) { return Arrays.toString(ints); }
tally(long... longs)1083     public static String tally(long... longs) { return Arrays.toString(longs); }
tally(float... floats)1084     public static String tally(float... floats) { return Arrays.toString(floats); }
tally(double... doubles)1085     public static String tally(double... doubles) { return Arrays.toString(doubles); }
tally(Float f0, Float... floats)1086     public static String tally(Float f0, Float... floats) {
1087       return f0 + ", " + Arrays.toString(floats);
1088     }
tally(String s0, String... strings)1089     public static String tally(String s0, String... strings) {
1090       return s0 + ", " + Arrays.toString(strings);
1091     }
tally(char c, Number... numbers)1092     public static String tally(char c, Number... numbers) {
1093       return c + ", " + Arrays.toString(numbers);
1094     }
1095     @SafeVarargs
tally(ArrayList<Integer> l0, ArrayList<Integer>... lists)1096     public static String tally(ArrayList<Integer> l0, ArrayList<Integer>... lists) {
1097       return Arrays.toString(l0.toArray()) + ", " + Arrays.deepToString(lists);
1098     }
tally(List l0, List... lists)1099     public static String tally(List l0, List... lists) {
1100       return Arrays.deepToString(l0.toArray()) + ", " + Arrays.deepToString(lists);
1101     }
foo(int... ints)1102     public static void foo(int... ints) { System.out.println(Arrays.toString(ints)); }
sumToPrimitive(int... ints)1103     public static long sumToPrimitive(int... ints) {
1104       long result = 0;
1105       for (int i : ints) result += i;
1106       return result;
1107     }
sumToReference(int... ints)1108     public static Long sumToReference(int... ints) {
1109       System.out.println("Hi");
1110       return new Long(sumToPrimitive(ints));
1111     }
lookup()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.
getAsObject(String[] strings)1118   public static Object getAsObject(String[] strings) {
1119     return (Object) strings;
1120   }
1121 
testVariableArity()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.
testVariableArity_MethodHandles_bind()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 
testRevealDirect()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