blob: aab9f50be74c5ef74b204c1d6fdefc6711622e93 [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;
Orion Hodson0d781e62016-11-04 11:09:53 +000022import java.nio.charset.Charset;
23import java.nio.charset.StandardCharsets;
Narayan Kamath9bdaeeb2016-10-20 10:57:45 +010024
Narayan Kamathe5eb5742016-11-02 14:16:27 +000025import java.lang.reflect.Constructor;
26import java.lang.reflect.Field;
27import java.lang.reflect.Method;
28
Narayan Kamath9bdaeeb2016-10-20 10:57:45 +010029public class Main {
30
31 public static class A {
32 public void foo() {
33 System.out.println("foo_A");
34 }
35
36 public static final Lookup lookup = MethodHandles.lookup();
37 }
38
39 public static class B extends A {
40 public void foo() {
41 System.out.println("foo_B");
42 }
43
44 public static final Lookup lookup = MethodHandles.lookup();
45 }
46
47 public static class C extends B {
48 public static final Lookup lookup = MethodHandles.lookup();
49 }
50
51 public static class D {
52 private final void privateRyan() {
53 System.out.println("privateRyan_D");
54 }
55
56 public static final Lookup lookup = MethodHandles.lookup();
57 }
58
59 public static class E extends D {
60 public static final Lookup lookup = MethodHandles.lookup();
61 }
62
63 public static void main(String[] args) throws Throwable {
64 testfindSpecial_invokeSuperBehaviour();
65 testfindSpecial_invokeDirectBehaviour();
Narayan Kamath3e0dce02016-10-31 13:55:55 +000066 testExceptionDetailMessages();
Narayan Kamath94bee022016-11-01 10:57:15 +000067 testfindVirtual();
Narayan Kamathe5eb5742016-11-02 14:16:27 +000068 testUnreflects();
Narayan Kamath0a8485e2016-11-02 18:47:11 +000069 testAsType();
Orion Hodson0d781e62016-11-04 11:09:53 +000070 testConstructors();
71 testStringConstructors();
Orion Hodson1a06f9f2016-11-09 08:32:42 +000072 testReturnValueConversions();
Narayan Kamath9bdaeeb2016-10-20 10:57:45 +010073 }
74
75 public static void testfindSpecial_invokeSuperBehaviour() throws Throwable {
76 // This is equivalent to an invoke-super instruction where the referrer
77 // is B.class.
78 MethodHandle mh1 = B.lookup.findSpecial(A.class /* refC */, "foo",
79 MethodType.methodType(void.class), B.class /* specialCaller */);
80
81 A aInstance = new A();
82 B bInstance = new B();
83 C cInstance = new C();
84
85 // This should be as if an invoke-super was called from one of B's methods.
86 mh1.invokeExact(bInstance);
87 mh1.invoke(bInstance);
88
89 // This should not work. The receiver type in the handle will be suitably
90 // restricted to B and subclasses.
91 try {
92 mh1.invoke(aInstance);
93 System.out.println("mh1.invoke(aInstance) should not succeeed");
94 } catch (ClassCastException expected) {
95 }
96
97 try {
98 mh1.invokeExact(aInstance);
99 System.out.println("mh1.invoke(aInstance) should not succeeed");
100 } catch (WrongMethodTypeException expected) {
Narayan Kamath9bdaeeb2016-10-20 10:57:45 +0100101 }
102
103 // This should *still* be as if an invoke-super was called from one of C's
104 // methods, despite the fact that we're operating on a C.
105 mh1.invoke(cInstance);
106
107 // Now that C is the special caller, the next invoke will call B.foo.
108 MethodHandle mh2 = C.lookup.findSpecial(A.class /* refC */, "foo",
109 MethodType.methodType(void.class), C.class /* specialCaller */);
110 mh2.invokeExact(cInstance);
111
112 // Shouldn't allow invoke-super semantics from an unrelated special caller.
113 try {
114 C.lookup.findSpecial(A.class, "foo",
115 MethodType.methodType(void.class), D.class /* specialCaller */);
116 System.out.println("findSpecial(A.class, foo, .. D.class) unexpectedly succeeded.");
117 } catch (IllegalAccessException expected) {
118 }
119 }
120
121 public static void testfindSpecial_invokeDirectBehaviour() throws Throwable {
122 D dInstance = new D();
123
124 MethodHandle mh3 = D.lookup.findSpecial(D.class, "privateRyan",
125 MethodType.methodType(void.class), D.class /* specialCaller */);
126 mh3.invoke(dInstance);
127
128 // The private method shouldn't be accessible from any special caller except
129 // itself...
130 try {
131 D.lookup.findSpecial(D.class, "privateRyan", MethodType.methodType(void.class), C.class);
132 System.out.println("findSpecial(privateRyan, C.class) unexpectedly succeeded");
133 } catch (IllegalAccessException expected) {
134 }
135
136 // ... or from any lookup context except its own.
137 try {
138 E.lookup.findSpecial(D.class, "privateRyan", MethodType.methodType(void.class), E.class);
139 System.out.println("findSpecial(privateRyan, E.class) unexpectedly succeeded");
140 } catch (IllegalAccessException expected) {
141 }
142 }
Narayan Kamath3e0dce02016-10-31 13:55:55 +0000143
144 public static void testExceptionDetailMessages() throws Throwable {
145 MethodHandle handle = MethodHandles.lookup().findVirtual(String.class, "concat",
146 MethodType.methodType(String.class, String.class));
147
148 try {
149 handle.invokeExact("a", new Object());
150 System.out.println("invokeExact(\"a\", new Object()) unexpectedly succeeded.");
151 } catch (WrongMethodTypeException ex) {
152 System.out.println("Received exception: " + ex.getMessage());
153 }
154 }
Narayan Kamath94bee022016-11-01 10:57:15 +0000155
156 public interface Foo {
157 public String foo();
158 }
159
160 public interface Bar extends Foo {
161 public String bar();
162 }
163
164 public static class BarSuper {
165 public String superPublicMethod() {
166 return "superPublicMethod";
167 }
168
169 public String superProtectedMethod() {
170 return "superProtectedMethod";
171 }
172
173 String superPackageMethod() {
174 return "superPackageMethod";
175 }
176 }
177
178 public static class BarImpl extends BarSuper implements Bar {
179 public BarImpl() {
180 }
181
182 @Override
183 public String foo() {
184 return "foo";
185 }
186
187 @Override
188 public String bar() {
189 return "bar";
190 }
191
192 private String privateMethod() { return "privateMethod"; }
193
194 public static String staticMethod() { return null; }
195
196 static final MethodHandles.Lookup lookup = MethodHandles.lookup();
197 }
198
199 public static void testfindVirtual() throws Throwable {
200 // Virtual lookups on static methods should not succeed.
201 try {
202 MethodHandles.lookup().findVirtual(
203 BarImpl.class, "staticMethod", MethodType.methodType(String.class));
204 System.out.println("findVirtual(staticMethod) unexpectedly succeeded");
205 } catch (IllegalAccessException expected) {
206 }
207
208 // Virtual lookups on private methods should not succeed, unless the Lookup
209 // context had sufficient privileges.
210 try {
211 MethodHandles.lookup().findVirtual(
212 BarImpl.class, "privateMethod", MethodType.methodType(String.class));
213 System.out.println("findVirtual(privateMethod) unexpectedly succeeded");
214 } catch (IllegalAccessException expected) {
215 }
216
217 // Virtual lookup on a private method with a context that *does* have sufficient
218 // privileges.
219 MethodHandle mh = BarImpl.lookup.findVirtual(
220 BarImpl.class, "privateMethod", MethodType.methodType(String.class));
221 String str = (String) mh.invoke(new BarImpl());
222 if (!"privateMethod".equals(str)) {
223 System.out.println("Unexpected return value for BarImpl#privateMethod: " + str);
224 }
225
226 // Find virtual must find interface methods defined by interfaces implemented
227 // by the class.
228 mh = MethodHandles.lookup().findVirtual(BarImpl.class, "foo",
229 MethodType.methodType(String.class));
230 str = (String) mh.invoke(new BarImpl());
231 if (!"foo".equals(str)) {
232 System.out.println("Unexpected return value for BarImpl#foo: " + str);
233 }
234
235 // .. and their super-interfaces.
236 mh = MethodHandles.lookup().findVirtual(BarImpl.class, "bar",
237 MethodType.methodType(String.class));
238 str = (String) mh.invoke(new BarImpl());
239 if (!"bar".equals(str)) {
240 System.out.println("Unexpected return value for BarImpl#bar: " + str);
241 }
242
243 // TODO(narayan): Fix this case, we're using the wrong ArtMethod for the
244 // invoke resulting in a failing check in the interpreter.
245 //
246 // mh = MethodHandles.lookup().findVirtual(Bar.class, "bar",
247 // MethodType.methodType(String.class));
248 // str = (String) mh.invoke(new BarImpl());
249 // if (!"bar".equals(str)) {
250 // System.out.println("Unexpected return value for BarImpl#bar: " + str);
251 // }
252
253 // We should also be able to lookup public / protected / package methods in
254 // the super class, given sufficient access privileges.
255 mh = MethodHandles.lookup().findVirtual(BarImpl.class, "superPublicMethod",
256 MethodType.methodType(String.class));
257 str = (String) mh.invoke(new BarImpl());
258 if (!"superPublicMethod".equals(str)) {
259 System.out.println("Unexpected return value for BarImpl#superPublicMethod: " + str);
260 }
261
262 mh = MethodHandles.lookup().findVirtual(BarImpl.class, "superProtectedMethod",
263 MethodType.methodType(String.class));
264 str = (String) mh.invoke(new BarImpl());
265 if (!"superProtectedMethod".equals(str)) {
266 System.out.println("Unexpected return value for BarImpl#superProtectedMethod: " + str);
267 }
268
269 mh = MethodHandles.lookup().findVirtual(BarImpl.class, "superPackageMethod",
270 MethodType.methodType(String.class));
271 str = (String) mh.invoke(new BarImpl());
272 if (!"superPackageMethod".equals(str)) {
273 System.out.println("Unexpected return value for BarImpl#superPackageMethod: " + str);
274 }
275 }
Narayan Kamathe5eb5742016-11-02 14:16:27 +0000276
277 static class UnreflectTester {
278 public String publicField;
279 private String privateField;
280
281 public static String publicStaticField = "publicStaticValue";
282 private static String privateStaticField = "privateStaticValue";
283
284 private UnreflectTester(String val) {
285 publicField = val;
286 privateField = val;
287 }
288
289 // NOTE: The boolean constructor argument only exists to give this a
290 // different signature.
291 public UnreflectTester(String val, boolean unused) {
292 this(val);
293 }
294
295 private static String privateStaticMethod() {
296 return "privateStaticMethod";
297 }
298
299 private String privateMethod() {
300 return "privateMethod";
301 }
302
303 public static String publicStaticMethod() {
304 return "publicStaticMethod";
305 }
306
307 public String publicMethod() {
308 return "publicMethod";
309 }
310 }
311
312 public static void testUnreflects() throws Throwable {
313 UnreflectTester instance = new UnreflectTester("unused");
314 Method publicMethod = UnreflectTester.class.getMethod("publicMethod");
315
316 MethodHandle mh = MethodHandles.lookup().unreflect(publicMethod);
317 assertEquals("publicMethod", (String) mh.invoke(instance));
318 assertEquals("publicMethod", (String) mh.invokeExact(instance));
319
320 Method publicStaticMethod = UnreflectTester.class.getMethod("publicStaticMethod");
321 mh = MethodHandles.lookup().unreflect(publicStaticMethod);
322 assertEquals("publicStaticMethod", (String) mh.invoke());
323 assertEquals("publicStaticMethod", (String) mh.invokeExact());
324
325 Method privateMethod = UnreflectTester.class.getDeclaredMethod("privateMethod");
326 try {
327 mh = MethodHandles.lookup().unreflect(privateMethod);
328 fail();
329 } catch (IllegalAccessException expected) {}
330
331 privateMethod.setAccessible(true);
332 mh = MethodHandles.lookup().unreflect(privateMethod);
333 assertEquals("privateMethod", (String) mh.invoke(instance));
334 assertEquals("privateMethod", (String) mh.invokeExact(instance));
335
336 Method privateStaticMethod = UnreflectTester.class.getDeclaredMethod("privateStaticMethod");
337 try {
338 mh = MethodHandles.lookup().unreflect(privateStaticMethod);
339 fail();
340 } catch (IllegalAccessException expected) {}
341
342 privateStaticMethod.setAccessible(true);
343 mh = MethodHandles.lookup().unreflect(privateStaticMethod);
344 assertEquals("privateStaticMethod", (String) mh.invoke());
345 assertEquals("privateStaticMethod", (String) mh.invokeExact());
346
347 Constructor privateConstructor = UnreflectTester.class.getDeclaredConstructor(String.class);
348 try {
349 mh = MethodHandles.lookup().unreflectConstructor(privateConstructor);
350 fail();
351 } catch (IllegalAccessException expected) {}
352
353 privateConstructor.setAccessible(true);
354 mh = MethodHandles.lookup().unreflectConstructor(privateConstructor);
Orion Hodson0d781e62016-11-04 11:09:53 +0000355 instance = (UnreflectTester) mh.invokeExact("abc");
356 assertEquals("abc", instance.publicField);
357 instance = (UnreflectTester) mh.invoke("def");
358 assertEquals("def", instance.publicField);
Narayan Kamathe5eb5742016-11-02 14:16:27 +0000359 Constructor publicConstructor = UnreflectTester.class.getConstructor(String.class,
360 boolean.class);
361 mh = MethodHandles.lookup().unreflectConstructor(publicConstructor);
Orion Hodson0d781e62016-11-04 11:09:53 +0000362 instance = (UnreflectTester) mh.invokeExact("abc", false);
363 assertEquals("abc", instance.publicField);
364 instance = (UnreflectTester) mh.invoke("def", true);
365 assertEquals("def", instance.publicField);
Narayan Kamathe5eb5742016-11-02 14:16:27 +0000366
367 // TODO(narayan): Non exact invokes for field sets/gets are not implemented yet.
368 //
369 // assertEquals("instanceValue", (String) mh.invoke(new UnreflectTester("instanceValue")));
370 Field publicField = UnreflectTester.class.getField("publicField");
371 mh = MethodHandles.lookup().unreflectGetter(publicField);
372 instance = new UnreflectTester("instanceValue");
373 assertEquals("instanceValue", (String) mh.invokeExact(instance));
374
375 mh = MethodHandles.lookup().unreflectSetter(publicField);
376 instance = new UnreflectTester("instanceValue");
377 mh.invokeExact(instance, "updatedInstanceValue");
378 assertEquals("updatedInstanceValue", instance.publicField);
379
380 Field publicStaticField = UnreflectTester.class.getField("publicStaticField");
381 mh = MethodHandles.lookup().unreflectGetter(publicStaticField);
382 UnreflectTester.publicStaticField = "updatedStaticValue";
383 assertEquals("updatedStaticValue", (String) mh.invokeExact());
384
385 mh = MethodHandles.lookup().unreflectSetter(publicStaticField);
386 UnreflectTester.publicStaticField = "updatedStaticValue";
387 mh.invokeExact("updatedStaticValue2");
388 assertEquals("updatedStaticValue2", UnreflectTester.publicStaticField);
389
390 Field privateField = UnreflectTester.class.getDeclaredField("privateField");
391 try {
392 mh = MethodHandles.lookup().unreflectGetter(privateField);
393 fail();
394 } catch (IllegalAccessException expected) {
395 }
396 try {
397 mh = MethodHandles.lookup().unreflectSetter(privateField);
398 fail();
399 } catch (IllegalAccessException expected) {
400 }
401
402 privateField.setAccessible(true);
403
404 mh = MethodHandles.lookup().unreflectGetter(privateField);
405 instance = new UnreflectTester("instanceValue");
406 assertEquals("instanceValue", (String) mh.invokeExact(instance));
407
408 mh = MethodHandles.lookup().unreflectSetter(privateField);
409 instance = new UnreflectTester("instanceValue");
410 mh.invokeExact(instance, "updatedInstanceValue");
411 assertEquals("updatedInstanceValue", instance.privateField);
412
413 Field privateStaticField = UnreflectTester.class.getDeclaredField("privateStaticField");
414 try {
415 mh = MethodHandles.lookup().unreflectGetter(privateStaticField);
416 fail();
417 } catch (IllegalAccessException expected) {
418 }
419 try {
420 mh = MethodHandles.lookup().unreflectSetter(privateStaticField);
421 fail();
422 } catch (IllegalAccessException expected) {
423 }
424
425 privateStaticField.setAccessible(true);
426 mh = MethodHandles.lookup().unreflectGetter(privateStaticField);
427 privateStaticField.set(null, "updatedStaticValue");
428 assertEquals("updatedStaticValue", (String) mh.invokeExact());
429
430 mh = MethodHandles.lookup().unreflectSetter(privateStaticField);
431 privateStaticField.set(null, "updatedStaticValue");
432 mh.invokeExact("updatedStaticValue2");
433 assertEquals("updatedStaticValue2", (String) privateStaticField.get(null));
434 }
435
Narayan Kamath0a8485e2016-11-02 18:47:11 +0000436 // This method only exists to fool Jack's handling of types. See b/32536744.
437 public static CharSequence getSequence() {
438 return "foo";
439 }
440
441 public static void testAsType() throws Throwable {
442 // The type of this handle is (String, String)String.
443 MethodHandle mh = MethodHandles.lookup().findVirtual(String.class,
444 "concat", MethodType.methodType(String.class, String.class));
445
446 // Change it to (CharSequence, String)Object.
447 MethodHandle asType = mh.asType(
448 MethodType.methodType(Object.class, CharSequence.class, String.class));
449
450 Object obj = asType.invokeExact((CharSequence) getSequence(), "bar");
451 assertEquals("foobar", (String) obj);
452
453 // Should fail due to a wrong return type.
454 try {
455 String str = (String) asType.invokeExact((CharSequence) getSequence(), "bar");
456 fail();
457 } catch (WrongMethodTypeException expected) {
458 }
459
460 // Should fail due to a wrong argument type (String instead of Charsequence).
461 try {
462 String str = (String) asType.invokeExact("baz", "bar");
463 fail();
464 } catch (WrongMethodTypeException expected) {
465 }
466
467 // Calls to asType should fail if the types are not convertible.
468 //
469 // Bad return type conversion.
470 try {
471 mh.asType(MethodType.methodType(int.class, String.class, String.class));
472 fail();
473 } catch (WrongMethodTypeException expected) {
474 }
475
476 // Bad argument conversion.
477 try {
478 mh.asType(MethodType.methodType(String.class, int.class, String.class));
479 fail();
480 } catch (WrongMethodTypeException expected) {
481 }
482 }
483
Narayan Kamathe5eb5742016-11-02 14:16:27 +0000484 public static void assertEquals(String s1, String s2) {
485 if (s1 == s2) {
486 return;
487 }
488
489 if (s1 != null && s2 != null && s1.equals(s2)) {
490 return;
491 }
492
493 throw new AssertionError("assertEquals s1: " + s1 + ", s2: " + s2);
494 }
495
496 public static void fail() {
497 System.out.println("fail");
498 Thread.dumpStack();
499 }
Orion Hodson0d781e62016-11-04 11:09:53 +0000500
501 public static void fail(String message) {
502 System.out.println("fail: " + message);
503 Thread.dumpStack();
504 }
505
506 public static void testConstructors() throws Throwable {
507 MethodHandle mh =
508 MethodHandles.lookup().findConstructor(Float.class,
509 MethodType.methodType(void.class,
510 float.class));
511 Float value = (Float) mh.invokeExact(0.33f);
512 if (value.floatValue() != 0.33f) {
513 fail("Unexpected float value from invokeExact " + value.floatValue());
514 }
515
516 value = (Float) mh.invoke(3.34f);
517 if (value.floatValue() != 3.34f) {
518 fail("Unexpected float value from invoke " + value.floatValue());
519 }
520
521 mh = MethodHandles.lookup().findConstructor(Double.class,
522 MethodType.methodType(void.class, String.class));
523 Double d = (Double) mh.invoke("8.45e3");
524 if (d.doubleValue() != 8.45e3) {
525 fail("Unexpected double value from Double(String) " + value.doubleValue());
526 }
527
528 mh = MethodHandles.lookup().findConstructor(Double.class,
529 MethodType.methodType(void.class, double.class));
530 d = (Double) mh.invoke(8.45e3);
531 if (d.doubleValue() != 8.45e3) {
532 fail("Unexpected double value from Double(double) " + value.doubleValue());
533 }
534
535 // Primitive type
536 try {
537 mh = MethodHandles.lookup().findConstructor(int.class, MethodType.methodType(void.class));
538 fail("Unexpected lookup success for primitive constructor");
539 } catch (NoSuchMethodException e) {}
540
541 // Interface
542 try {
543 mh = MethodHandles.lookup().findConstructor(Readable.class,
544 MethodType.methodType(void.class));
545 fail("Unexpected lookup success for interface constructor");
546 } catch (NoSuchMethodException e) {}
547
548 // Abstract
549 mh = MethodHandles.lookup().findConstructor(Process.class, MethodType.methodType(void.class));
550 try {
551 mh.invoke();
552 fail("Unexpected ability to instantiate an abstract class");
553 } catch (InstantiationException e) {}
554
555 // Non-existent
556 try {
557 MethodHandle bad = MethodHandles.lookup().findConstructor(
558 String.class, MethodType.methodType(String.class, Float.class));
559 fail("Unexpected success for non-existent constructor");
560 } catch (NoSuchMethodException e) {}
561
562 // Non-void constructor search. (I)I instead of (I)V.
563 try {
564 MethodHandle foo = MethodHandles.lookup().findConstructor(
565 Integer.class, MethodType.methodType(Integer.class, Integer.class));
566 fail("Unexpected success for non-void type for findConstructor");
567 } catch (NoSuchMethodException e) {}
568 }
569
570 public static void testStringConstructors() throws Throwable {
571 final String testPattern = "The system as we know it is broken";
572
573 // String()
574 MethodHandle mh = MethodHandles.lookup().findConstructor(
575 String.class, MethodType.methodType(void.class));
576 String s = (String) mh.invokeExact();
577 if (!s.equals("")) {
578 fail("Unexpected empty string constructor result: '" + s + "'");
579 }
580
581 // String(String)
582 mh = MethodHandles.lookup().findConstructor(
583 String.class, MethodType.methodType(void.class, String.class));
584 s = (String) mh.invokeExact(testPattern);
585 if (!s.equals(testPattern)) {
586 fail("Unexpected string constructor result: '" + s + "'");
587 }
588
589 // String(char[])
590 mh = MethodHandles.lookup().findConstructor(
591 String.class, MethodType.methodType(void.class, char[].class));
592 s = (String) mh.invokeExact(testPattern.toCharArray());
593 if (!s.equals(testPattern)) {
594 fail("Unexpected string constructor result: '" + s + "'");
595 }
596
597 // String(char[], int, int)
598 mh = MethodHandles.lookup().findConstructor(
599 String.class, MethodType.methodType(void.class, char[].class, int.class, int.class));
600 s = (String) mh.invokeExact(new char [] { 'a', 'b', 'c', 'd', 'e'}, 2, 3);
601 if (!s.equals("cde")) {
602 fail("Unexpected string constructor result: '" + s + "'");
603 }
604
605 // String(int[] codePoints, int offset, int count)
606 StringBuffer sb = new StringBuffer(testPattern);
607 int[] codePoints = new int[sb.codePointCount(0, sb.length())];
608 for (int i = 0; i < sb.length(); ++i) {
609 codePoints[i] = sb.codePointAt(i);
610 }
611 mh = MethodHandles.lookup().findConstructor(
612 String.class, MethodType.methodType(void.class, int[].class, int.class, int.class));
613 s = (String) mh.invokeExact(codePoints, 0, codePoints.length);
614 if (!s.equals(testPattern)) {
615 fail("Unexpected string constructor result: '" + s + "'");
616 }
617
618 // String(byte ascii[], int hibyte, int offset, int count)
619 byte [] ascii = testPattern.getBytes(StandardCharsets.US_ASCII);
620 mh = MethodHandles.lookup().findConstructor(
621 String.class, MethodType.methodType(void.class, byte[].class, int.class, int.class));
622 s = (String) mh.invokeExact(ascii, 0, ascii.length);
623 if (!s.equals(testPattern)) {
624 fail("Unexpected string constructor result: '" + s + "'");
625 }
626
627 // String(byte bytes[], int offset, int length, String charsetName)
628 mh = MethodHandles.lookup().findConstructor(
629 String.class,
630 MethodType.methodType(void.class, byte[].class, int.class, int.class, String.class));
631 s = (String) mh.invokeExact(ascii, 0, 5, StandardCharsets.US_ASCII.name());
632 if (!s.equals(testPattern.substring(0, 5))) {
633 fail("Unexpected string constructor result: '" + s + "'");
634 }
635
636 // String(byte bytes[], int offset, int length, Charset charset)
637 mh = MethodHandles.lookup().findConstructor(
638 String.class,
639 MethodType.methodType(void.class, byte[].class, int.class, int.class, Charset.class));
640 s = (String) mh.invokeExact(ascii, 0, 5, StandardCharsets.US_ASCII);
641 if (!s.equals(testPattern.substring(0, 5))) {
642 fail("Unexpected string constructor result: '" + s + "'");
643 }
644
645 // String(byte bytes[], String charsetName)
646 mh = MethodHandles.lookup().findConstructor(
647 String.class,
648 MethodType.methodType(void.class, byte[].class, String.class));
649 s = (String) mh.invokeExact(ascii, StandardCharsets.US_ASCII.name());
650 if (!s.equals(testPattern)) {
651 fail("Unexpected string constructor result: '" + s + "'");
652 }
653
654 // String(byte bytes[], Charset charset)
655 mh = MethodHandles.lookup().findConstructor(
656 String.class, MethodType.methodType(void.class, byte[].class, Charset.class));
657 s = (String) mh.invokeExact(ascii, StandardCharsets.US_ASCII);
658 if (!s.equals(testPattern)) {
659 fail("Unexpected string constructor result: '" + s + "'");
660 }
661
662 // String(byte bytes[], int offset, int length)
663 mh = MethodHandles.lookup().findConstructor(
664 String.class, MethodType.methodType(void.class, byte[].class, int.class, int.class));
665 s = (String) mh.invokeExact(ascii, 1, ascii.length - 2);
666 s = testPattern.charAt(0) + s + testPattern.charAt(testPattern.length() - 1);
667 if (!s.equals(testPattern)) {
668 fail("Unexpected string constructor result: '" + s + "'");
669 }
670
671 // String(byte bytes[])
672 mh = MethodHandles.lookup().findConstructor(
673 String.class, MethodType.methodType(void.class, byte[].class));
674 s = (String) mh.invokeExact(ascii);
675 if (!s.equals(testPattern)) {
676 fail("Unexpected string constructor result: '" + s + "'");
677 }
678
679 // String(StringBuffer buffer)
680 mh = MethodHandles.lookup().findConstructor(
681 String.class, MethodType.methodType(void.class, StringBuffer.class));
682 s = (String) mh.invokeExact(sb);
683 if (!s.equals(testPattern)) {
684 fail("Unexpected string constructor result: '" + s + "'");
685 }
686
687 System.out.println("String constructors done.");
688 }
Orion Hodson1a06f9f2016-11-09 08:32:42 +0000689
690 private static void testReferenceReturnValueConversions() throws Throwable {
691 MethodHandle mh = MethodHandles.lookup().findStatic(
692 Float.class, "valueOf", MethodType.methodType(Float.class, String.class));
693
694 // No conversion
695 Float f = (Float) mh.invokeExact("1.375");
696 if (f.floatValue() != 1.375) {
697 fail();
698 }
699 f = (Float) mh.invoke("1.875");
700 if (f.floatValue() != 1.875) {
701 fail();
702 }
703
704 // Bad conversion
705 try {
706 int i = (int) mh.invokeExact("7.77");
707 fail();
708 } catch (WrongMethodTypeException e) {}
709
710 try {
711 int i = (int) mh.invoke("7.77");
712 fail();
713 } catch (WrongMethodTypeException e) {}
714
715 // Assignment to super-class.
716 Number n = (Number) mh.invoke("1.11");
717 try {
718 Number o = (Number) mh.invokeExact("1.11");
719 fail();
720 } catch (WrongMethodTypeException e) {}
721
722 // Assignment to widened boxed primitive class.
723 try {
724 Double u = (Double) mh.invoke("1.11");
725 fail();
726 } catch (ClassCastException e) {}
727
728 try {
729 Double v = (Double) mh.invokeExact("1.11");
730 fail();
731 } catch (WrongMethodTypeException e) {}
732
733 // Unboxed
734 float p = (float) mh.invoke("1.11");
735 if (p != 1.11f) {
736 fail();
737 }
738
739 // Unboxed and widened
740 double d = (double) mh.invoke("2.5");
741 if (d != 2.5) {
742 fail();
743 }
744
745 // Interface
746 Comparable<Float> c = (Comparable<Float>) mh.invoke("2.125");
747 if (c.compareTo(new Float(2.125f)) != 0) {
748 fail();
749 }
750
751 System.out.println("testReferenceReturnValueConversions done.");
752 }
753
754 private static void testPrimitiveReturnValueConversions() throws Throwable {
755 MethodHandle mh = MethodHandles.lookup().findStatic(
756 Math.class, "min", MethodType.methodType(int.class, int.class, int.class));
757
758 final int SMALL = -8972;
759 final int LARGE = 7932529;
760
761 // No conversion
762 if ((int) mh.invokeExact(LARGE, SMALL) != SMALL) {
763 fail();
764 } else if ((int) mh.invoke(LARGE, SMALL) != SMALL) {
765 fail();
766 } else if ((int) mh.invokeExact(SMALL, LARGE) != SMALL) {
767 fail();
768 } else if ((int) mh.invoke(SMALL, LARGE) != SMALL) {
769 fail();
770 }
771
772 // int -> long
773 try {
774 if ((long) mh.invokeExact(LARGE, SMALL) != (long) SMALL) {}
775 fail();
776 } catch (WrongMethodTypeException e) {}
777
778 if ((long) mh.invoke(LARGE, SMALL) != (long) SMALL) {
779 fail();
780 }
781
782 // int -> short
783 try {
784 if ((short) mh.invokeExact(LARGE, SMALL) != (short) SMALL) {}
785 fail();
786 } catch (WrongMethodTypeException e) {}
787
788 try {
789 if ((short) mh.invoke(LARGE, SMALL) != (short) SMALL) {
790 fail();
791 }
792 } catch (WrongMethodTypeException e) {}
793
794 // int -> Integer
795 try {
796 if (!((Integer) mh.invokeExact(LARGE, SMALL)).equals(new Integer(SMALL))) {}
797 fail();
798 } catch (WrongMethodTypeException e) {}
799
800 if (!((Integer) mh.invoke(LARGE, SMALL)).equals(new Integer(SMALL))) {
801 fail();
802 }
803
804 // int -> Long
805 try {
806 Long l = (Long) mh.invokeExact(LARGE, SMALL);
807 fail();
808 } catch (WrongMethodTypeException e) {}
809
810 try {
811 Long l = (Long) mh.invoke(LARGE, SMALL);
812 fail();
813 } catch (WrongMethodTypeException e) {}
814
815 // int -> Short
816 try {
817 Short s = (Short) mh.invokeExact(LARGE, SMALL);
818 fail();
819 } catch (WrongMethodTypeException e) {}
820
821 try {
822 Short s = (Short) mh.invoke(LARGE, SMALL);
823 fail();
824 } catch (WrongMethodTypeException e) {}
825
826 // int -> Process
827 try {
828 Process p = (Process) mh.invokeExact(LARGE, SMALL);
829 fail();
830 } catch (WrongMethodTypeException e) {}
831
832 try {
833 Process p = (Process) mh.invoke(LARGE, SMALL);
834 fail();
835 } catch (WrongMethodTypeException e) {}
836
837 // void -> Object
838 mh = MethodHandles.lookup().findStatic(System.class, "gc", MethodType.methodType(void.class));
839 Object o = (Object) mh.invoke();
840 if (o != null) fail();
841
842 // void -> long
843 long l = (long) mh.invoke();
844 if (l != 0) fail();
845
Orion Hodsonf1412b42016-11-11 12:03:29 +0000846 // boolean -> Boolean
847 mh = MethodHandles.lookup().findStatic(Boolean.class, "parseBoolean",
848 MethodType.methodType(boolean.class, String.class));
849 Boolean z = (Boolean) mh.invoke("True");
850 if (!z.booleanValue()) fail();
851
852 // boolean -> int
853 try {
854 int dummy = (int) mh.invoke("True");
855 fail();
856 } catch (WrongMethodTypeException e) {}
857
858 // boolean -> Integer
859 try {
860 Integer dummy = (Integer) mh.invoke("True");
861 fail();
862 } catch (WrongMethodTypeException e) {}
863
864 // Boolean -> boolean
865 mh = MethodHandles.lookup().findStatic(Boolean.class, "valueOf",
866 MethodType.methodType(Boolean.class, boolean.class));
867 boolean w = (boolean) mh.invoke(false);
868 if (w) fail();
869
870 // Boolean -> int
871 try {
872 int dummy = (int) mh.invoke(false);
873 fail();
874 } catch (WrongMethodTypeException e) {}
875
876 // Boolean -> Integer
877 try {
878 Integer dummy = (Integer) mh.invoke("True");
879 fail();
880 } catch (WrongMethodTypeException e) {}
881
Orion Hodson1a06f9f2016-11-09 08:32:42 +0000882 System.out.println("testPrimitiveReturnValueConversions done.");
883 }
884
885 public static void testReturnValueConversions() throws Throwable {
886 testReferenceReturnValueConversions();
887 testPrimitiveReturnValueConversions();
888 }
Narayan Kamath9bdaeeb2016-10-20 10:57:45 +0100889}