1/* 2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26/* @test 27 * @bug 8139885 28 * @bug 8150824 29 * @bug 8150825 30 * @run testng/othervm -ea -esa test.java.lang.invoke.TryFinallyTest 31 */ 32 33package test.java.lang.invoke; 34 35import java.lang.invoke.MethodHandle; 36import java.lang.invoke.MethodHandles; 37import java.lang.invoke.MethodHandles.Lookup; 38import java.lang.invoke.MethodType; 39 40import static java.lang.invoke.MethodType.methodType; 41 42import static org.testng.AssertJUnit.*; 43 44import org.testng.annotations.*; 45 46/** 47 * Tests for the tryFinally method handle combinator introduced in JEP 274. 48 */ 49public class TryFinallyTest { 50 51 static final Lookup LOOKUP = MethodHandles.lookup(); 52 53 @Test 54 public static void testTryFinally() throws Throwable { 55 MethodHandle hello = MethodHandles.tryFinally(TryFinally.MH_greet, TryFinally.MH_exclaim); 56 assertEquals(TryFinally.MT_hello, hello.type()); 57 assertEquals("Hello, world!", hello.invoke("world")); 58 } 59 60 @Test 61 public static void testTryFinallyVoid() throws Throwable { 62 MethodHandle tfVoid = MethodHandles.tryFinally(TryFinally.MH_print, TryFinally.MH_printMore); 63 assertEquals(TryFinally.MT_printHello, tfVoid.type()); 64 tfVoid.invoke("world"); 65 } 66 67 @Test 68 public static void testTryFinallySublist() throws Throwable { 69 MethodHandle helloMore = MethodHandles.tryFinally(TryFinally.MH_greetMore, TryFinally.MH_exclaimMore); 70 assertEquals(TryFinally.MT_moreHello, helloMore.type()); 71 assertEquals("Hello, world and universe (but world first)!", helloMore.invoke("world", "universe")); 72 } 73 74 @DataProvider 75 static Object[][] omitTrailingArguments() { 76 MethodHandle c = TryFinally.MH_voidCleanup; 77 return new Object[][]{ 78 {c}, 79 {MethodHandles.dropArguments(c, 1, int.class)}, 80 {MethodHandles.dropArguments(c, 1, int.class, long.class)}, 81 {MethodHandles.dropArguments(c, 1, int.class, long.class, Object.class, int.class)}, 82 {MethodHandles.dropArguments(c, 1, int.class, long.class, Object.class, int.class, long.class)} 83 }; 84 } 85 86 @Test(dataProvider = "omitTrailingArguments") 87 public static void testTryFinallyOmitTrailingArguments(MethodHandle cleanup) throws Throwable { 88 MethodHandle tf = MethodHandles.tryFinally(TryFinally.MH_dummyTarget, cleanup); 89 tf.invoke(1, 2L, "a", 23, 42L, "b"); 90 } 91 92 @DataProvider 93 static Object[][] negativeTestData() { 94 MethodHandle intid = MethodHandles.identity(int.class); 95 MethodHandle intco = MethodHandles.constant(int.class, 0); 96 MethodHandle errTarget = MethodHandles.dropArguments(intco, 0, int.class, double.class, String.class, int.class); 97 MethodHandle errCleanup = MethodHandles.dropArguments(MethodHandles.constant(int.class, 0), 0, Throwable.class, 98 int.class, double.class, Object.class); 99 MethodHandle voidTarget = TryFinally.MH_voidTarget; 100 MethodHandle voidICleanup = MethodHandles.dropArguments(TryFinally.MH_voidCleanup, 1, int.class); 101 return new Object[][]{ 102 {intid, MethodHandles.identity(double.class), 103 "target and return types must match: double != int"}, 104 {intid, MethodHandles.dropArguments(intid, 0, String.class), 105 "cleanup first argument and Throwable must match: (String,int)int != class java.lang.Throwable"}, 106 {intid, MethodHandles.dropArguments(intid, 0, Throwable.class, double.class), 107 "cleanup second argument and target return type must match: (Throwable,double,int)int != int"}, 108 {errTarget, errCleanup, 109 "cleanup parameters after (Throwable,result) and target parameter list prefix must match: " + 110 errCleanup.type() + " != " + errTarget.type()}, 111 {voidTarget, voidICleanup, 112 "cleanup parameters after (Throwable,result) and target parameter list prefix must match: " + 113 voidICleanup.type() + " != " + voidTarget.type()} 114 }; 115 } 116 117 @Test(dataProvider = "negativeTestData") 118 public static void testTryFinallyNegative(MethodHandle target, MethodHandle cleanup, String expectedMessage) { 119 boolean caught = false; 120 try { 121 MethodHandles.tryFinally(target, cleanup); 122 } catch (IllegalArgumentException iae) { 123 assertEquals(expectedMessage, iae.getMessage()); 124 caught = true; 125 } 126 assertTrue(caught); 127 } 128 129 static class TryFinally { 130 131 static String greet(String whom) { 132 return "Hello, " + whom; 133 } 134 135 static String exclaim(Throwable t, String r, String whom) { 136 return r + "!"; 137 } 138 139 static void print(String what) { 140 System.out.print("Hello, " + what); 141 } 142 143 static void printMore(Throwable t, String what) { 144 System.out.println("!"); 145 } 146 147 static String greetMore(String first, String second) { 148 return "Hello, " + first + " and " + second; 149 } 150 151 static String exclaimMore(Throwable t, String r, String first) { 152 return r + " (but " + first + " first)!"; 153 } 154 155 static void voidTarget() {} 156 157 static void voidCleanup(Throwable t) {} 158 159 static final Class<TryFinally> TRY_FINALLY = TryFinally.class; 160 161 static final MethodType MT_greet = methodType(String.class, String.class); 162 static final MethodType MT_exclaim = methodType(String.class, Throwable.class, String.class, String.class); 163 static final MethodType MT_print = methodType(void.class, String.class); 164 static final MethodType MT_printMore = methodType(void.class, Throwable.class, String.class); 165 static final MethodType MT_greetMore = methodType(String.class, String.class, String.class); 166 static final MethodType MT_exclaimMore = methodType(String.class, Throwable.class, String.class, String.class); 167 static final MethodType MT_voidTarget = methodType(void.class); 168 static final MethodType MT_voidCleanup = methodType(void.class, Throwable.class); 169 170 static final MethodHandle MH_greet; 171 static final MethodHandle MH_exclaim; 172 static final MethodHandle MH_print; 173 static final MethodHandle MH_printMore; 174 static final MethodHandle MH_greetMore; 175 static final MethodHandle MH_exclaimMore; 176 static final MethodHandle MH_voidTarget; 177 static final MethodHandle MH_voidCleanup; 178 179 static final MethodHandle MH_dummyTarget; 180 181 static final MethodType MT_hello = methodType(String.class, String.class); 182 static final MethodType MT_printHello = methodType(void.class, String.class); 183 static final MethodType MT_moreHello = methodType(String.class, String.class, String.class); 184 185 static { 186 try { 187 MH_greet = LOOKUP.findStatic(TRY_FINALLY, "greet", MT_greet); 188 MH_exclaim = LOOKUP.findStatic(TRY_FINALLY, "exclaim", MT_exclaim); 189 MH_print = LOOKUP.findStatic(TRY_FINALLY, "print", MT_print); 190 MH_printMore = LOOKUP.findStatic(TRY_FINALLY, "printMore", MT_printMore); 191 MH_greetMore = LOOKUP.findStatic(TRY_FINALLY, "greetMore", MT_greetMore); 192 MH_exclaimMore = LOOKUP.findStatic(TRY_FINALLY, "exclaimMore", MT_exclaimMore); 193 MH_voidTarget = LOOKUP.findStatic(TRY_FINALLY, "voidTarget", MT_voidTarget); 194 MH_voidCleanup = LOOKUP.findStatic(TRY_FINALLY, "voidCleanup", MT_voidCleanup); 195 MH_dummyTarget = MethodHandles.dropArguments(MH_voidTarget, 0, int.class, long.class, Object.class, 196 int.class, long.class, Object.class); 197 } catch (Exception e) { 198 throw new ExceptionInInitializerError(e); 199 } 200 } 201 202 } 203 204} 205