Path: blob/master/test/jdk/java/lang/invoke/JavaDocExamplesTest.java
41149 views
/*1* Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/* @test24* @summary example code used in javadoc for java.lang.invoke API25* @compile JavaDocExamplesTest.java26* @run testng/othervm test.java.lang.invoke.JavaDocExamplesTest27*/2829package test.java.lang.invoke;3031import java.io.StringWriter;32import java.lang.invoke.*;33import static java.lang.invoke.MethodHandles.*;34import static java.lang.invoke.MethodType.*;3536import java.util.*;3738import org.testng.*;39import org.testng.annotations.*;4041/**42* @author jrose43*/44public class JavaDocExamplesTest {45/** Wrapper for running the TestNG tests in this module.46* Put TestNG on the classpath!47*/48public static void main(String... ignore) throws Throwable {49new JavaDocExamplesTest().run();50}5152public void run() throws Throwable {53testMisc();54testFindStatic();55testFindConstructor();56testFindVirtual();57testFindSpecial();58testPermuteArguments();59testZero();60testDropArguments();61testDropArgumentsToMatch();62testFilterArguments();63testFoldArguments();64testFoldArguments2();65testMethodHandlesSummary();66testAsSpreader();67testAsCollector();68testAsVarargsCollector();69testAsFixedArity();70testAsTypeCornerCases();71testMutableCallSite();72}73// How much output?74static final Class<?> THIS_CLASS = JavaDocExamplesTest.class;75static int verbosity = Integer.getInteger(THIS_CLASS.getSimpleName()+".verbosity", 0);767778{}79private static final Lookup LOOKUP = lookup();80// static final private MethodHandle CONCAT_1 = LOOKUP.findVirtual(String.class,81// "concat", methodType(String.class, String.class));82// static final private MethodHandle HASHCODE_1 = LOOKUP.findVirtual(Object.class,83// "hashCode", methodType(int.class));8485// form required if ReflectiveOperationException is intercepted:86private static final MethodHandle CONCAT_2, HASHCODE_2, ADD_2, SUB_2;87static {88try {89Class<?> THIS_CLASS = LOOKUP.lookupClass();90CONCAT_2 = LOOKUP.findVirtual(String.class,91"concat", methodType(String.class, String.class));92HASHCODE_2 = LOOKUP.findVirtual(Object.class,93"hashCode", methodType(int.class));94ADD_2 = LOOKUP.findStatic(THIS_CLASS, "add", methodType(int.class, int.class, int.class));95SUB_2 = LOOKUP.findStatic(THIS_CLASS, "sub", methodType(int.class, int.class, int.class));96} catch (ReflectiveOperationException ex) {97throw new RuntimeException(ex);98}99}100static int add(int x, int y) { return x + y; }101static int sub(int x, int y) { return x - y; }102103{}104105@Test public void testMisc() throws Throwable {106// Extra tests, not from javadoc:107{}108MethodHandle CONCAT_3 = LOOKUP.findVirtual(String.class,109"concat", methodType(String.class, String.class));110MethodHandle HASHCODE_3 = LOOKUP.findVirtual(Object.class,111"hashCode", methodType(int.class));112//assertEquals("xy", (String) CONCAT_1.invokeExact("x", "y"));113assertEquals("xy", (String) CONCAT_2.invokeExact("x", "y"));114assertEquals("xy", (String) CONCAT_3.invokeExact("x", "y"));115//assertEquals("xy".hashCode(), (int) HASHCODE_1.invokeExact((Object)"xy"));116assertEquals("xy".hashCode(), (int) HASHCODE_2.invokeExact((Object)"xy"));117assertEquals("xy".hashCode(), (int) HASHCODE_3.invokeExact((Object)"xy"));118{}119}120121@Test public void testFindStatic() throws Throwable {122{}123MethodHandle MH_asList = publicLookup().findStatic(Arrays.class,124"asList", methodType(List.class, Object[].class));125assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());126{}127}128129@Test public void testFindVirtual() throws Throwable {130{}131MethodHandle MH_concat = publicLookup().findVirtual(String.class,132"concat", methodType(String.class, String.class));133MethodHandle MH_hashCode = publicLookup().findVirtual(Object.class,134"hashCode", methodType(int.class));135MethodHandle MH_hashCode_String = publicLookup().findVirtual(String.class,136"hashCode", methodType(int.class));137assertEquals("xy", (String) MH_concat.invokeExact("x", "y"));138assertEquals("xy".hashCode(), (int) MH_hashCode.invokeExact((Object)"xy"));139assertEquals("xy".hashCode(), (int) MH_hashCode_String.invokeExact("xy"));140// interface method:141MethodHandle MH_subSequence = publicLookup().findVirtual(CharSequence.class,142"subSequence", methodType(CharSequence.class, int.class, int.class));143assertEquals("def", MH_subSequence.invoke("abcdefghi", 3, 6).toString());144// constructor "internal method" must be accessed differently:145MethodType MT_newString = methodType(void.class); //()V for new String()146try { assertEquals("impossible", lookup()147.findVirtual(String.class, "<init>", MT_newString));148} catch (NoSuchMethodException ex) { } // OK149MethodHandle MH_newString = publicLookup()150.findConstructor(String.class, MT_newString);151assertEquals("", (String) MH_newString.invokeExact());152{}153}154155@Test public void testFindConstructor() throws Throwable {156{}157MethodHandle MH_newArrayList = publicLookup().findConstructor(158ArrayList.class, methodType(void.class, Collection.class));159Collection orig = Arrays.asList("x", "y");160Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig);161assert(orig != copy);162assertEquals(orig, copy);163// a variable-arity constructor:164MethodHandle MH_newProcessBuilder = publicLookup().findConstructor(165ProcessBuilder.class, methodType(void.class, String[].class));166ProcessBuilder pb = (ProcessBuilder)167MH_newProcessBuilder.invoke("x", "y", "z");168assertEquals("[x, y, z]", pb.command().toString());169{}170}171172// for testFindSpecial173{}174static class Listie extends ArrayList {175public String toString() { return "[wee Listie]"; }176static Lookup lookup() { return MethodHandles.lookup(); }177}178{}179180@Test public void testFindSpecial() throws Throwable {181{}182// no access to constructor via invokeSpecial:183MethodHandle MH_newListie = Listie.lookup()184.findConstructor(Listie.class, methodType(void.class));185Listie l = (Listie) MH_newListie.invokeExact();186try { assertEquals("impossible", Listie.lookup().findSpecial(187Listie.class, "<init>", methodType(void.class), Listie.class));188} catch (NoSuchMethodException ex) { } // OK189// access to super and self methods via invokeSpecial:190MethodHandle MH_super = Listie.lookup().findSpecial(191ArrayList.class, "toString" , methodType(String.class), Listie.class);192MethodHandle MH_this = Listie.lookup().findSpecial(193Listie.class, "toString" , methodType(String.class), Listie.class);194MethodHandle MH_duper = Listie.lookup().findSpecial(195Object.class, "toString" , methodType(String.class), Listie.class);196assertEquals("[]", (String) MH_super.invokeExact(l));197assertEquals(""+l, (String) MH_this.invokeExact(l));198assertEquals("[]", (String) MH_duper.invokeExact(l)); // ArrayList method199try { assertEquals("inaccessible", Listie.lookup().findSpecial(200String.class, "toString", methodType(String.class), Listie.class));201} catch (IllegalAccessException ex) { } // OK202Listie subl = new Listie() { public String toString() { return "[subclass]"; } };203assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method204{}205}206207@Test public void testPermuteArguments() throws Throwable {208{{209{} /// JAVADOC210MethodType intfn1 = methodType(int.class, int.class);211MethodType intfn2 = methodType(int.class, int.class, int.class);212MethodHandle sub = SUB_2;// ... {int x, int y => x-y} ...;213assert(sub.type().equals(intfn2));214MethodHandle sub1 = permuteArguments(sub, intfn2, 0, 1);215MethodHandle rsub = permuteArguments(sub, intfn2, 1, 0);216assert((int)rsub.invokeExact(1, 100) == 99);217MethodHandle add = ADD_2;// ... {int x, int y => x+y} ...;218assert(add.type().equals(intfn2));219MethodHandle twice = permuteArguments(add, intfn1, 0, 0);220assert(twice.type().equals(intfn1));221assert((int)twice.invokeExact(21) == 42);222}}223{{224{} /// JAVADOC225MethodHandle cat = lookup().findVirtual(String.class,226"concat", methodType(String.class, String.class));227assertEquals("xy", (String) cat.invokeExact("x", "y"));228MethodHandle d0 = dropArguments(cat, 0, String.class);229assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));230MethodHandle d1 = dropArguments(cat, 1, String.class);231assertEquals("xz", (String) d1.invokeExact("x", "y", "z"));232MethodHandle d2 = dropArguments(cat, 2, String.class);233assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));234MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);235assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));236}}237}238239@Test public void testZero() throws Throwable {240{{241{} /// JAVADOC242Class<?> type = Double.class;243MethodHandle mh1 = MethodHandles.explicitCastArguments(MethodHandles.constant(Object.class, null), methodType(type));244assertEquals("()Double", mh1.type().toString());245MethodHandle mh2 = MethodHandles.empty(methodType(type));246assertEquals("()Double", mh2.type().toString());247}}248}249250@Test public void testDropArguments() throws Throwable {251{{252{} /// JAVADOC253MethodHandle cat = lookup().findVirtual(String.class,254"concat", methodType(String.class, String.class));255assertEquals("xy", (String) cat.invokeExact("x", "y"));256MethodType bigType = cat.type().insertParameterTypes(0, int.class, String.class);257MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2));258assertEquals(bigType, d0.type());259assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));260}}261{{262{} /// JAVADOC263MethodHandle cat = lookup().findVirtual(String.class,264"concat", methodType(String.class, String.class));265assertEquals("xy", (String) cat.invokeExact("x", "y"));266MethodHandle d0 = dropArguments(cat, 0, String.class);267assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));268MethodHandle d1 = dropArguments(cat, 1, String.class);269assertEquals("xz", (String) d1.invokeExact("x", "y", "z"));270MethodHandle d2 = dropArguments(cat, 2, String.class);271assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));272MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);273assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));274}}275}276277@Test public void testDropArgumentsToMatch() throws Throwable {278{{279{} /// JAVADOC280MethodHandle h0= constant(boolean.class, true);281MethodHandle h1 = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class));282MethodType bigType = h1.type().insertParameterTypes(1, String.class, int.class);283MethodHandle h2 = dropArguments(h1, 0, bigType.parameterList());284if (h1.type().parameterCount() < h2.type().parameterCount()) {285h1 = dropArgumentsToMatch(h1, 0, h2.type().parameterList(), 0); // lengthen h1286}287else {288h2 = dropArgumentsToMatch(h2, 0, h1.type().parameterList(), 0); // lengthen h2289}290MethodHandle h3 = guardWithTest(h0, h1, h2);291assertEquals("xy", h3.invoke("x", "y", 1, "a", "b", "c"));292}}293}294295@Test public void testFilterArguments() throws Throwable {296{{297{} /// JAVADOC298MethodHandle cat = lookup().findVirtual(String.class,299"concat", methodType(String.class, String.class));300MethodHandle upcase = lookup().findVirtual(String.class,301"toUpperCase", methodType(String.class));302assertEquals("xy", (String) cat.invokeExact("x", "y"));303MethodHandle f0 = filterArguments(cat, 0, upcase);304assertEquals("Xy", (String) f0.invokeExact("x", "y")); // Xy305MethodHandle f1 = filterArguments(cat, 1, upcase);306assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY307MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);308assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY309}}310}311312@Test public void testCollectArguments() throws Throwable {313{{314{} /// JAVADOC315MethodHandle deepToString = publicLookup()316.findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));317MethodHandle ts1 = deepToString.asCollector(String[].class, 1);318assertEquals("[strange]", (String) ts1.invokeExact("strange"));319MethodHandle ts2 = deepToString.asCollector(String[].class, 2);320assertEquals("[up, down]", (String) ts2.invokeExact("up", "down"));321MethodHandle ts3 = deepToString.asCollector(String[].class, 3);322MethodHandle ts3_ts2 = collectArguments(ts3, 1, ts2);323assertEquals("[top, [up, down], strange]",324(String) ts3_ts2.invokeExact("top", "up", "down", "strange"));325MethodHandle ts3_ts2_ts1 = collectArguments(ts3_ts2, 3, ts1);326assertEquals("[top, [up, down], [strange]]",327(String) ts3_ts2_ts1.invokeExact("top", "up", "down", "strange"));328MethodHandle ts3_ts2_ts3 = collectArguments(ts3_ts2, 1, ts3);329assertEquals("[top, [[up, down, strange], charm], bottom]",330(String) ts3_ts2_ts3.invokeExact("top", "up", "down", "strange", "charm", "bottom"));331}}332}333334@Test public void testFoldArguments() throws Throwable {335{{336{} /// JAVADOC337MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,338"println", methodType(void.class, String.class))339.bindTo(System.out);340MethodHandle cat = lookup().findVirtual(String.class,341"concat", methodType(String.class, String.class));342assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));343MethodHandle catTrace = foldArguments(cat, trace);344// also prints "boo":345assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));346}}347}348349static void assertEquals(Object exp, Object act) {350if (verbosity > 0)351System.out.println("result: "+act);352Assert.assertEquals(exp, act);353}354355static void assertTrue(boolean b) {356if (verbosity > 0) {357System.out.println("result: " + b);358}359Assert.assertTrue(b);360}361362@Test public void testMethodHandlesSummary() throws Throwable {363{{364{} /// JAVADOC365Object x, y; String s; int i;366MethodType mt; MethodHandle mh;367MethodHandles.Lookup lookup = MethodHandles.lookup();368// mt is (char,char)String369mt = MethodType.methodType(String.class, char.class, char.class);370mh = lookup.findVirtual(String.class, "replace", mt);371s = (String) mh.invokeExact("daddy",'d','n');372// invokeExact(Ljava/lang/String;CC)Ljava/lang/String;373assertEquals(s, "nanny");374// weakly typed invocation (using MHs.invoke)375s = (String) mh.invokeWithArguments("sappy", 'p', 'v');376assertEquals(s, "savvy");377// mt is (Object[])List378mt = MethodType.methodType(java.util.List.class, Object[].class);379mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);380assert(mh.isVarargsCollector());381x = mh.invoke("one", "two");382// invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;383assertEquals(x, java.util.Arrays.asList("one","two"));384// mt is (Object,Object,Object)Object385mt = MethodType.genericMethodType(3);386mh = mh.asType(mt);387x = mh.invokeExact((Object)1, (Object)2, (Object)3);388// invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;389assertEquals(x, java.util.Arrays.asList(1,2,3));390// mt is ()int391mt = MethodType.methodType(int.class);392mh = lookup.findVirtual(java.util.List.class, "size", mt);393i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3));394// invokeExact(Ljava/util/List;)I395assert(i == 3);396mt = MethodType.methodType(void.class, String.class);397mh = lookup.findVirtual(java.io.PrintStream.class, "println", mt);398mh.invokeExact(System.out, "Hello, world.");399// invokeExact(Ljava/io/PrintStream;Ljava/lang/String;)V400{}401}}402}403404@Test public void testAsSpreader() throws Throwable {405{{406{} /// JAVADOC407MethodHandle equals = publicLookup()408.findVirtual(String.class, "equals", methodType(boolean.class, Object.class));409assert( (boolean) equals.invokeExact("me", (Object)"me"));410assert(!(boolean) equals.invokeExact("me", (Object)"thee"));411// spread both arguments from a 2-array:412MethodHandle eq2 = equals.asSpreader(Object[].class, 2);413assert( (boolean) eq2.invokeExact(new Object[]{ "me", "me" }));414assert(!(boolean) eq2.invokeExact(new Object[]{ "me", "thee" }));415// try to spread from anything but a 2-array:416for (int n = 0; n <= 10; n++) {417Object[] badArityArgs = (n == 2 ? new Object[0] : new Object[n]);418try { assert((boolean) eq2.invokeExact(badArityArgs) && false); }419catch (IllegalArgumentException ex) { } // OK420}421// spread both arguments from a String array:422MethodHandle eq2s = equals.asSpreader(String[].class, 2);423assert( (boolean) eq2s.invokeExact(new String[]{ "me", "me" }));424assert(!(boolean) eq2s.invokeExact(new String[]{ "me", "thee" }));425// spread second arguments from a 1-array:426MethodHandle eq1 = equals.asSpreader(Object[].class, 1);427assert( (boolean) eq1.invokeExact("me", new Object[]{ "me" }));428assert(!(boolean) eq1.invokeExact("me", new Object[]{ "thee" }));429// spread no arguments from a 0-array or null:430MethodHandle eq0 = equals.asSpreader(Object[].class, 0);431assert( (boolean) eq0.invokeExact("me", (Object)"me", new Object[0]));432assert(!(boolean) eq0.invokeExact("me", (Object)"thee", (Object[])null));433// asSpreader and asCollector are approximate inverses:434for (int n = 0; n <= 2; n++) {435for (Class<?> a : new Class<?>[]{Object[].class, String[].class, CharSequence[].class}) {436MethodHandle equals2 = equals.asSpreader(a, n).asCollector(a, n);437assert( (boolean) equals2.invokeWithArguments("me", "me"));438assert(!(boolean) equals2.invokeWithArguments("me", "thee"));439}440}441MethodHandle caToString = publicLookup()442.findStatic(Arrays.class, "toString", methodType(String.class, char[].class));443assertEquals("[A, B, C]", (String) caToString.invokeExact("ABC".toCharArray()));444MethodHandle caString3 = caToString.asCollector(char[].class, 3);445assertEquals("[A, B, C]", (String) caString3.invokeExact('A', 'B', 'C'));446MethodHandle caToString2 = caString3.asSpreader(char[].class, 2);447assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray()));448}}449}450451@Test public void testAsCollector() throws Throwable {452{{453{} /// JAVADOC454MethodHandle deepToString = publicLookup()455.findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));456assertEquals("[won]", (String) deepToString.invokeExact(new Object[]{"won"}));457MethodHandle ts1 = deepToString.asCollector(Object[].class, 1);458assertEquals(methodType(String.class, Object.class), ts1.type());459//assertEquals("[won]", (String) ts1.invokeExact( new Object[]{"won"})); //FAIL460assertEquals("[[won]]", (String) ts1.invokeExact((Object) new Object[]{"won"}));461// arrayType can be a subtype of Object[]462MethodHandle ts2 = deepToString.asCollector(String[].class, 2);463assertEquals(methodType(String.class, String.class, String.class), ts2.type());464assertEquals("[two, too]", (String) ts2.invokeExact("two", "too"));465MethodHandle ts0 = deepToString.asCollector(Object[].class, 0);466assertEquals("[]", (String) ts0.invokeExact());467// collectors can be nested, Lisp-style468MethodHandle ts22 = deepToString.asCollector(Object[].class, 3).asCollector(String[].class, 2);469assertEquals("[A, B, [C, D]]", ((String) ts22.invokeExact((Object)'A', (Object)"B", "C", "D")));470// arrayType can be any primitive array type471MethodHandle bytesToString = publicLookup()472.findStatic(Arrays.class, "toString", methodType(String.class, byte[].class))473.asCollector(byte[].class, 3);474assertEquals("[1, 2, 3]", (String) bytesToString.invokeExact((byte)1, (byte)2, (byte)3));475MethodHandle longsToString = publicLookup()476.findStatic(Arrays.class, "toString", methodType(String.class, long[].class))477.asCollector(long[].class, 1);478assertEquals("[123]", (String) longsToString.invokeExact((long)123));479}}480}481482@SuppressWarnings("rawtypes")483@Test public void testAsVarargsCollector() throws Throwable {484{{485{} /// JAVADOC486MethodHandle deepToString = publicLookup()487.findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));488MethodHandle ts1 = deepToString.asVarargsCollector(Object[].class);489assertEquals("[won]", (String) ts1.invokeExact( new Object[]{"won"}));490assertEquals("[won]", (String) ts1.invoke( new Object[]{"won"}));491assertEquals("[won]", (String) ts1.invoke( "won" ));492assertEquals("[[won]]", (String) ts1.invoke((Object) new Object[]{"won"}));493// findStatic of Arrays.asList(...) produces a variable arity method handle:494MethodHandle asList = publicLookup()495.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class));496assertEquals(methodType(List.class, Object[].class), asList.type());497assert(asList.isVarargsCollector());498assertEquals("[]", asList.invoke().toString());499assertEquals("[1]", asList.invoke(1).toString());500assertEquals("[two, too]", asList.invoke("two", "too").toString());501String[] argv = { "three", "thee", "tee" };502assertEquals("[three, thee, tee]", asList.invoke(argv).toString());503assertEquals("[three, thee, tee]", asList.invoke((Object[])argv).toString());504List ls = (List) asList.invoke((Object)argv);505assertEquals(1, ls.size());506assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0)));507}}508}509510@Test public void testAsFixedArity() throws Throwable {511{{512{} /// JAVADOC513MethodHandle asListVar = publicLookup()514.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))515.asVarargsCollector(Object[].class);516MethodHandle asListFix = asListVar.asFixedArity();517assertEquals("[1]", asListVar.invoke(1).toString());518Exception caught = null;519try { asListFix.invoke((Object)1); }520catch (Exception ex) { caught = ex; }521assert(caught instanceof ClassCastException);522assertEquals("[two, too]", asListVar.invoke("two", "too").toString());523try { asListFix.invoke("two", "too"); }524catch (Exception ex) { caught = ex; }525assert(caught instanceof WrongMethodTypeException);526Object[] argv = { "three", "thee", "tee" };527assertEquals("[three, thee, tee]", asListVar.invoke(argv).toString());528assertEquals("[three, thee, tee]", asListFix.invoke(argv).toString());529assertEquals(1, ((List) asListVar.invoke((Object)argv)).size());530assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());531}}532}533534@Test public void testAsTypeCornerCases() throws Throwable {535{{536{} /// JAVADOC537MethodHandle i2s = publicLookup()538.findVirtual(Integer.class, "toString", methodType(String.class));539i2s = i2s.asType(i2s.type().unwrap());540MethodHandle l2s = publicLookup()541.findVirtual(Long.class, "toString", methodType(String.class));542l2s = l2s.asType(l2s.type().unwrap());543544Exception caught = null;545try { i2s.asType(methodType(String.class, String.class)); }546catch (Exception ex) { caught = ex; }547assert(caught instanceof WrongMethodTypeException);548549i2s.asType(methodType(String.class, byte.class));550i2s.asType(methodType(String.class, Byte.class));551i2s.asType(methodType(String.class, Character.class));552i2s.asType(methodType(String.class, Integer.class));553l2s.asType(methodType(String.class, byte.class));554l2s.asType(methodType(String.class, Byte.class));555l2s.asType(methodType(String.class, Character.class));556l2s.asType(methodType(String.class, Integer.class));557l2s.asType(methodType(String.class, Long.class));558559caught = null;560try { i2s.asType(methodType(String.class, Long.class)); }561catch (Exception ex) { caught = ex; }562assert(caught instanceof WrongMethodTypeException);563564MethodHandle i2sGen = i2s.asType(methodType(String.class, Object.class));565MethodHandle l2sGen = l2s.asType(methodType(String.class, Object.class));566567i2sGen.invoke(42); // int -> Integer -> Object -> Integer -> int568i2sGen.invoke((byte)4); // byte -> Byte -> Object -> Byte -> byte -> int569l2sGen.invoke(42); // int -> Integer -> Object -> Integer -> int570l2sGen.invoke((byte)4); // byte -> Byte -> Object -> Byte -> byte -> int571l2sGen.invoke(0x420000000L);572573caught = null;574try { i2sGen.invoke(0x420000000L); } // long -> Long -> Object -> Integer CCE575catch (Exception ex) { caught = ex; }576assert(caught instanceof ClassCastException);577578caught = null;579try { i2sGen.invoke("asdf"); } // String -> Object -> Integer CCE580catch (Exception ex) { caught = ex; }581assert(caught instanceof ClassCastException);582{}583}}584}585586@Test public void testMutableCallSite() throws Throwable {587{{588{} /// JAVADOC589MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));590MethodHandle MH_name = name.dynamicInvoker();591MethodType MT_str1 = MethodType.methodType(String.class);592MethodHandle MH_upcase = MethodHandles.lookup()593.findVirtual(String.class, "toUpperCase", MT_str1);594MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase);595name.setTarget(MethodHandles.constant(String.class, "Rocky"));596assertEquals("ROCKY", (String) worker1.invokeExact());597name.setTarget(MethodHandles.constant(String.class, "Fred"));598assertEquals("FRED", (String) worker1.invokeExact());599// (mutation can be continued indefinitely)600/*601* </pre></blockquote>602* <p>603* The same call site may be used in several places at once.604* <blockquote><pre>605*/606MethodType MT_str2 = MethodType.methodType(String.class, String.class);607MethodHandle MH_cat = lookup().findVirtual(String.class,608"concat", methodType(String.class, String.class));609MethodHandle MH_dear = MethodHandles.insertArguments(MH_cat, 1, ", dear?");610MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear);611assertEquals("Fred, dear?", (String) worker2.invokeExact());612name.setTarget(MethodHandles.constant(String.class, "Wilma"));613assertEquals("WILMA", (String) worker1.invokeExact());614assertEquals("Wilma, dear?", (String) worker2.invokeExact());615{}616}}617}618619@Test public void testSwitchPoint() throws Throwable {620{{621{} /// JAVADOC622MethodHandle MH_strcat = MethodHandles.lookup()623.findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class));624SwitchPoint spt = new SwitchPoint();625assert(!spt.hasBeenInvalidated());626// the following steps may be repeated to re-use the same switch point:627MethodHandle worker1 = MH_strcat;628MethodHandle worker2 = MethodHandles.permuteArguments(MH_strcat, MH_strcat.type(), 1, 0);629MethodHandle worker = spt.guardWithTest(worker1, worker2);630assertEquals("method", (String) worker.invokeExact("met", "hod"));631SwitchPoint.invalidateAll(new SwitchPoint[]{ spt });632assert(spt.hasBeenInvalidated());633assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));634{}635}}636}637638@Test public void testFoldArguments2() throws Throwable {639{{640{} /// JAVADOC641// argument-based dispatch for methods of the form boolean x.___(y: String)642Lookup lookup = publicLookup();643// first, a tracing hack:644MethodHandle println = lookup.findVirtual(java.io.PrintStream.class, "println", methodType(void.class, String.class));645MethodHandle arrayToString = lookup.findStatic(Arrays.class, "toString", methodType(String.class, Object[].class));646MethodHandle concat = lookup.findVirtual(String.class, "concat", methodType(String.class, String.class));647MethodHandle arrayToString_DIS = filterReturnValue(arrayToString, concat.bindTo("DIS:"));648MethodHandle arrayToString_INV = filterReturnValue(arrayToString, concat.bindTo("INV:"));649MethodHandle printArgs_DIS = filterReturnValue(arrayToString_DIS, println.bindTo(System.out)).asVarargsCollector(Object[].class);650MethodHandle printArgs_INV = filterReturnValue(arrayToString_INV, println.bindTo(System.out)).asVarargsCollector(Object[].class);651// metaobject protocol:652MethodType mtype = methodType(boolean.class, String.class);653MethodHandle findVirtual = lookup.findVirtual(Lookup.class,654"findVirtual", methodType(MethodHandle.class, Class.class, String.class, MethodType.class));655MethodHandle getClass = lookup.findVirtual(Object.class,656"getClass", methodType(Class.class));657MethodHandle dispatch = findVirtual;658dispatch = filterArguments(dispatch, 1, getClass);659dispatch = insertArguments(dispatch, 3, mtype);660dispatch = dispatch.bindTo(lookup);661assertEquals(methodType(MethodHandle.class, Object.class, String.class), dispatch.type());662MethodHandle invoker = invoker(mtype.insertParameterTypes(0, Object.class));663// wrap tracing around the dispatch and invoke steps:664dispatch = foldArguments(dispatch, printArgs_DIS.asType(dispatch.type().changeReturnType(void.class)));665invoker = foldArguments(invoker, printArgs_INV.asType(invoker.type().changeReturnType(void.class)));666invoker = dropArguments(invoker, 2, String.class); // ignore selector667// compose the dispatcher and the invoker:668MethodHandle invokeDispatched = foldArguments(invoker, dispatch);669Object x = "football", y = new java.util.Scanner("bar");670assert( (boolean) invokeDispatched.invokeExact(x, "startsWith", "foo"));671assert(!(boolean) invokeDispatched.invokeExact(x, "startsWith", "#"));672assert( (boolean) invokeDispatched.invokeExact(x, "endsWith", "all"));673assert(!(boolean) invokeDispatched.invokeExact(x, "endsWith", "foo"));674assert( (boolean) invokeDispatched.invokeExact(y, "hasNext", "[abc]+[rst]"));675assert(!(boolean) invokeDispatched.invokeExact(y, "hasNext", "[123]+[789]"));676}}677}678679static int one(int k) { return 1; }680static int inc(int i, int acc, int k) { return i + 1; }681static int mult(int i, int acc, int k) { return i * acc; }682static boolean pred(int i, int acc, int k) { return i < k; }683static int fin(int i, int acc, int k) { return acc; }684685@Test public void testLoop() throws Throwable {686MethodHandle MH_inc, MH_one, MH_mult, MH_pred, MH_fin;687Class<?> I = int.class;688MH_inc = LOOKUP.findStatic(THIS_CLASS, "inc", methodType(I, I, I, I));689MH_one = LOOKUP.findStatic(THIS_CLASS, "one", methodType(I, I));690MH_mult = LOOKUP.findStatic(THIS_CLASS, "mult", methodType(I, I, I, I));691MH_pred = LOOKUP.findStatic(THIS_CLASS, "pred", methodType(boolean.class, I, I, I));692MH_fin = LOOKUP.findStatic(THIS_CLASS, "fin", methodType(I, I, I, I));693{{694{} /// JAVADOC695// iterative implementation of the factorial function as a loop handle696// null initializer for counter, should initialize to 0697MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc};698MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin};699MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);700assertEquals(120, loop.invoke(5));701{}702}}703}704705static int inc(int i) { return i + 1; } // drop acc, k706static int mult(int i, int acc) { return i * acc; } //drop k707static boolean cmp(int i, int k) { return i < k; }708709@Test public void testSimplerLoop() throws Throwable {710MethodHandle MH_inc, MH_mult, MH_cmp;711Class<?> I = int.class;712MH_inc = LOOKUP.findStatic(THIS_CLASS, "inc", methodType(I, I));713MH_mult = LOOKUP.findStatic(THIS_CLASS, "mult", methodType(I, I, I));714MH_cmp = LOOKUP.findStatic(THIS_CLASS, "cmp", methodType(boolean.class, I, I));715{{716{} /// JAVADOC717// simplified implementation of the factorial function as a loop handle718// null initializer for counter, should initialize to 0719MethodHandle MH_one = MethodHandles.constant(int.class, 1);720MethodHandle MH_pred = MethodHandles.dropArguments(MH_cmp, 1, int.class); // drop acc721MethodHandle MH_fin = MethodHandles.dropArguments(MethodHandles.identity(int.class), 0, int.class); // drop i722MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc};723MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin};724MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);725assertEquals(720, loop.invoke(6));726{}727}}728}729730// for testFacLoop731{}732static class FacLoop {733final int k;734FacLoop(int k) { this.k = k; }735int inc(int i) { return i + 1; }736int mult(int i, int acc) { return i * acc; }737boolean pred(int i) { return i < k; }738int fin(int i, int acc) { return acc; }739}740{}741742// assume MH_inc, MH_mult, and MH_pred are handles to the above methods743@Test public void testFacLoop() throws Throwable {744MethodHandle MH_FacLoop, MH_inc, MH_mult, MH_pred, MH_fin;745Class<?> I = int.class;746MH_FacLoop = LOOKUP.findConstructor(FacLoop.class, methodType(void.class, I));747MH_inc = LOOKUP.findVirtual(FacLoop.class, "inc", methodType(I, I));748MH_mult = LOOKUP.findVirtual(FacLoop.class, "mult", methodType(I, I, I));749MH_pred = LOOKUP.findVirtual(FacLoop.class, "pred", methodType(boolean.class, I));750MH_fin = LOOKUP.findVirtual(FacLoop.class, "fin", methodType(I, I, I));751{{752{} /// JAVADOC753// instance-based implementation of the factorial function as a loop handle754// null initializer for counter, should initialize to 0755MethodHandle MH_one = MethodHandles.constant(int.class, 1);756MethodHandle[] instanceClause = new MethodHandle[]{MH_FacLoop};757MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc};758MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin};759MethodHandle loop = MethodHandles.loop(instanceClause, counterClause, accumulatorClause);760assertEquals(5040, loop.invoke(7));761{}762}}763}764765static List<String> initZip(Iterator<String> a, Iterator<String> b) { return new ArrayList<>(); }766static boolean zipPred(List<String> zip, Iterator<String> a, Iterator<String> b) { return a.hasNext() && b.hasNext(); }767static List<String> zipStep(List<String> zip, Iterator<String> a, Iterator<String> b) {768zip.add(a.next());769zip.add(b.next());770return zip;771}772773@Test public void testWhileLoop() throws Throwable {774MethodHandle MH_initZip, MH_zipPred, MH_zipStep;775Class<?> IT = Iterator.class;776Class<?> L = List.class;777MH_initZip = LOOKUP.findStatic(THIS_CLASS, "initZip", methodType(L, IT, IT));778MH_zipPred = LOOKUP.findStatic(THIS_CLASS, "zipPred", methodType(boolean.class, L, IT, IT));779MH_zipStep = LOOKUP.findStatic(THIS_CLASS, "zipStep", methodType(L, L, IT, IT));780{{781{} /// JAVADOC782// implement the zip function for lists as a loop handle783MethodHandle loop = MethodHandles.whileLoop(MH_initZip, MH_zipPred, MH_zipStep);784List<String> a = Arrays.asList("a", "b", "c", "d");785List<String> b = Arrays.asList("e", "f", "g", "h");786List<String> zipped = Arrays.asList("a", "e", "b", "f", "c", "g", "d", "h");787assertEquals(zipped, (List<String>) loop.invoke(a.iterator(), b.iterator()));788{}789}}790}791792static int zero(int limit) { return 0; }793static int step(int i, int limit) { return i + 1; }794static boolean pred(int i, int limit) { return i < limit; }795796@Test public void testDoWhileLoop() throws Throwable {797MethodHandle MH_zero, MH_step, MH_pred;798Class<?> I = int.class;799MH_zero = LOOKUP.findStatic(THIS_CLASS, "zero", methodType(I, I));800MH_step = LOOKUP.findStatic(THIS_CLASS, "step", methodType(I, I, I));801MH_pred = LOOKUP.findStatic(THIS_CLASS, "pred", methodType(boolean.class, I, I));802{{803{} /// JAVADOC804// int i = 0; while (i < limit) { ++i; } return i; => limit805MethodHandle loop = MethodHandles.doWhileLoop(MH_zero, MH_step, MH_pred);806assertEquals(23, loop.invoke(23));807{}808}}809}810811static String step(String v, int counter, String start_) { return "na " + v; } //#0812static String step(String v, int counter ) { return "na " + v; } //#1813static String step(String v, int counter, int iterations_, String pre, String start_) { return pre + " " + v; } //#2814static String step3(String v, int counter, String pre) { return pre + " " + v; } //#3815816@Test public void testCountedLoop() throws Throwable {817MethodHandle MH_step;818Class<?> S = String.class, I = int.class;819// Theme:820MH_step = LOOKUP.findStatic(THIS_CLASS, "step", methodType(S, S, I, S));821{{822{} /// JAVADOC823// String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s;824// => a variation on a well known theme825MethodHandle fit13 = MethodHandles.constant(int.class, 13);826MethodHandle start = MethodHandles.identity(String.class);827MethodHandle loop = MethodHandles.countedLoop(fit13, start, MH_step); // (v, i, _) -> "na " + v828assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("Lambdaman!"));829{}830}}831// Variation #1:832MH_step = LOOKUP.findStatic(THIS_CLASS, "step", methodType(S, S, I));833{{834{} /// JAVADOC835// String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s;836// => a variation on a well known theme837MethodHandle count = MethodHandles.dropArguments(MethodHandles.identity(int.class), 1, String.class);838MethodHandle start = MethodHandles.dropArguments(MethodHandles.identity(String.class), 0, int.class);839MethodHandle loop = MethodHandles.countedLoop(count, start, MH_step); // (v, i) -> "na " + v840assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke(13, "Lambdaman!"));841{}842assertEquals("na na Lambdaman!", loop.invoke(2, "Lambdaman!"));843assertEquals("Lambdaman!", loop.invoke(0, "Lambdaman!"));844assertEquals("Lambdaman!", loop.invoke(-1, "Lambdaman!"));845assertEquals("Lambdaman!", loop.invoke(Integer.MIN_VALUE, "Lambdaman!"));846}}847// Variation #2:848MH_step = LOOKUP.findStatic(THIS_CLASS, "step", methodType(S, S, I, I, S, S));849{{850{} /// JAVADOC851// String s = "Lambdaman!", t = "na"; for (int i = 0; i < 13; ++i) { s = t + " " + s; } return s;852// => a variation on a well known theme853MethodHandle count = MethodHandles.identity(int.class);854MethodHandle start = MethodHandles.dropArguments(MethodHandles.identity(String.class), 0, int.class, String.class);855MethodHandle loop = MethodHandles.countedLoop(count, start, MH_step); // (v, i, _, pre, _) -> pre + " " + v856assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke(13, "na", "Lambdaman!"));857{}858}}859// Variation #3:860MH_step = LOOKUP.findStatic(THIS_CLASS, "step3", methodType(S, S, I, S));861{{862{} /// JAVADOC863// String s = "Lambdaman!", t = "na"; for (int i = 0; i < 13; ++i) { s = t + " " + s; } return s;864// => a variation on a well known theme865MethodType loopType = methodType(String.class, String.class, int.class, String.class);866MethodHandle count = MethodHandles.dropArgumentsToMatch(MethodHandles.identity(int.class), 0, loopType.parameterList(), 1);867MethodHandle start = MethodHandles.dropArgumentsToMatch(MethodHandles.identity(String.class), 0, loopType.parameterList(), 2);868MethodHandle body = MethodHandles.dropArgumentsToMatch(MH_step, 2, loopType.parameterList(), 0);869MethodHandle loop = MethodHandles.countedLoop(count, start, body); // (v, i, pre, _, _) -> pre + " " + v870assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("na", 13, "Lambdaman!"));871{}872}}873}874875static List<String> reverseStep(List<String> r, String e) {876r.add(0, e);877return r;878}879static List<String> newArrayList() { return new ArrayList<>(); }880881@Test public void testIteratedLoop() throws Throwable {882MethodHandle MH_newArrayList, MH_reverseStep;883Class<?> L = List.class, S = String.class;884MH_newArrayList = LOOKUP.findStatic(THIS_CLASS, "newArrayList", methodType(L));885MH_reverseStep = LOOKUP.findStatic(THIS_CLASS, "reverseStep", methodType(L, L, S));886{{887{} /// JAVADOC888// reverse a list889MethodHandle loop = MethodHandles.iteratedLoop(null, MH_newArrayList, MH_reverseStep);890List<String> list = Arrays.asList("a", "b", "c", "d", "e");891List<String> reversedList = Arrays.asList("e", "d", "c", "b", "a");892assertEquals(reversedList, (List<String>) loop.invoke(list));893{}894}}895}896897@Test public void testFoldArguments3() throws Throwable {898{{899{} /// JAVADOC900MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,901"println", methodType(void.class, String.class))902.bindTo(System.out);903MethodHandle cat = lookup().findVirtual(String.class,904"concat", methodType(String.class, String.class));905assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));906MethodHandle catTrace = foldArguments(cat, 1, trace);907// also prints "jum":908assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));909{}910}}911}912913@Test public void testAsCollector2() throws Throwable {914{{915{} /// JAVADOC916StringWriter swr = new StringWriter();917MethodHandle swWrite = LOOKUP.findVirtual(StringWriter.class, "write", methodType(void.class, char[].class, int.class, int.class)).bindTo(swr);918MethodHandle swWrite4 = swWrite.asCollector(0, char[].class, 4);919swWrite4.invoke('A', 'B', 'C', 'D', 1, 2);920assertEquals("BC", swr.toString());921swWrite4.invoke('P', 'Q', 'R', 'S', 0, 4);922assertEquals("BCPQRS", swr.toString());923swWrite4.invoke('W', 'X', 'Y', 'Z', 3, 1);924assertEquals("BCPQRSZ", swr.toString());925{}926}}927}928929@Test public void testAsSpreader2() throws Throwable {930{{931{} /// JAVADOC932MethodHandle compare = LOOKUP.findStatic(Objects.class, "compare", methodType(int.class, Object.class, Object.class, Comparator.class));933MethodHandle compare2FromArray = compare.asSpreader(0, Object[].class, 2);934Object[] ints = new Object[]{3, 9, 7, 7};935Comparator<Integer> cmp = (a, b) -> a - b;936assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 0, 2), cmp) < 0);937assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 1, 3), cmp) > 0);938assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 2, 4), cmp) == 0);939{}940}}941}942943/* ---- TEMPLATE ----944@Test public void testFoo() throws Throwable {945{{946{} /// JAVADOC947{}948}}949}950*/951}952953954