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