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