| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| import java.lang.invoke.MethodHandle; |
| import java.lang.invoke.MethodHandles; |
| import java.lang.invoke.MethodHandles.Lookup; |
| import java.lang.invoke.MethodType; |
| import java.lang.invoke.WrongMethodTypeException; |
| |
| public class Main { |
| public static void main(String[] args) throws Throwable { |
| testThrowException(); |
| testDropArguments(); |
| testCatchException(); |
| testGuardWithTest(); |
| } |
| |
| public static void testThrowException() throws Throwable { |
| MethodHandle handle = MethodHandles.throwException(String.class, |
| IllegalArgumentException.class); |
| |
| if (handle.type().returnType() != String.class) { |
| System.out.println("Unexpected return type for handle: " + handle + |
| " [ " + handle.type() + "]"); |
| } |
| |
| final IllegalArgumentException iae = new IllegalArgumentException("boo!"); |
| try { |
| handle.invoke(iae); |
| System.out.println("Expected an exception of type: java.lang.IllegalArgumentException"); |
| } catch (IllegalArgumentException expected) { |
| if (expected != iae) { |
| System.out.println("Wrong exception: expected " + iae + " but was " + expected); |
| } |
| } |
| } |
| |
| public static void dropArguments_delegate(String message, long message2) { |
| System.out.println("Message: " + message + ", Message2: " + message2); |
| } |
| |
| public static void testDropArguments() throws Throwable { |
| MethodHandle delegate = MethodHandles.lookup().findStatic(Main.class, |
| "dropArguments_delegate", |
| MethodType.methodType(void.class, new Class<?>[] { String.class, long.class })); |
| |
| MethodHandle transform = MethodHandles.dropArguments(delegate, 0, int.class, Object.class); |
| |
| // The transformer will accept two additional arguments at position zero. |
| try { |
| transform.invokeExact("foo", 42l); |
| fail(); |
| } catch (WrongMethodTypeException expected) { |
| } |
| |
| transform.invokeExact(45, new Object(), "foo", 42l); |
| transform.invoke(45, new Object(), "foo", 42l); |
| |
| // Additional arguments at position 1. |
| transform = MethodHandles.dropArguments(delegate, 1, int.class, Object.class); |
| transform.invokeExact("foo", 45, new Object(), 42l); |
| transform.invoke("foo", 45, new Object(), 42l); |
| |
| // Additional arguments at position 2. |
| transform = MethodHandles.dropArguments(delegate, 2, int.class, Object.class); |
| transform.invokeExact("foo", 42l, 45, new Object()); |
| transform.invoke("foo", 42l, 45, new Object()); |
| |
| // Note that we still perform argument conversions even for the arguments that |
| // are subsequently dropped. |
| try { |
| transform.invoke("foo", 42l, 45l, new Object()); |
| fail(); |
| } catch (WrongMethodTypeException expected) { |
| } catch (IllegalArgumentException expected) { |
| // TODO(narayan): We currently throw the wrong type of exception here, |
| // it's IAE and should be WMTE instead. |
| } |
| |
| // Check that asType works as expected. |
| transform = MethodHandles.dropArguments(delegate, 0, int.class, Object.class); |
| transform = transform.asType(MethodType.methodType(void.class, |
| new Class<?>[] { short.class, Object.class, String.class, long.class })); |
| transform.invokeExact((short) 45, new Object(), "foo", 42l); |
| |
| // Invalid argument location, should not be allowed. |
| try { |
| MethodHandles.dropArguments(delegate, -1, int.class, Object.class); |
| fail(); |
| } catch (IllegalArgumentException expected) { |
| } |
| |
| // Invalid argument location, should not be allowed. |
| try { |
| MethodHandles.dropArguments(delegate, 3, int.class, Object.class); |
| fail(); |
| } catch (IllegalArgumentException expected) { |
| } |
| |
| try { |
| MethodHandles.dropArguments(delegate, 1, void.class); |
| fail(); |
| } catch (IllegalArgumentException expected) { |
| } |
| } |
| |
| public static String testCatchException_target(String arg1, long arg2, String exceptionMessage) |
| throws Throwable { |
| if (exceptionMessage != null) { |
| throw new IllegalArgumentException(exceptionMessage); |
| } |
| |
| System.out.println("Target: Arg1: " + arg1 + ", Arg2: " + arg2); |
| return "target"; |
| } |
| |
| public static String testCatchException_handler(IllegalArgumentException iae, String arg1, long arg2, |
| String exMsg) { |
| System.out.println("Handler: " + iae + ", Arg1: " + arg1 + ", Arg2: " + arg2 + ", ExMsg: " + exMsg); |
| return "handler1"; |
| } |
| |
| public static String testCatchException_handler2(IllegalArgumentException iae, String arg1) { |
| System.out.println("Handler: " + iae + ", Arg1: " + arg1); |
| return "handler2"; |
| } |
| |
| public static void testCatchException() throws Throwable { |
| MethodHandle target = MethodHandles.lookup().findStatic(Main.class, |
| "testCatchException_target", |
| MethodType.methodType(String.class, new Class<?>[] { String.class, long.class, String.class })); |
| |
| MethodHandle handler = MethodHandles.lookup().findStatic(Main.class, |
| "testCatchException_handler", |
| MethodType.methodType(String.class, new Class<?>[] { IllegalArgumentException.class, |
| String.class, long.class, String.class })); |
| |
| MethodHandle adapter = MethodHandles.catchException(target, IllegalArgumentException.class, |
| handler); |
| |
| String returnVal = null; |
| |
| // These two should end up calling the target always. We're passing a null exception |
| // message here, which means the target will not throw. |
| returnVal = (String) adapter.invoke("foo", 42, null); |
| assertEquals("target", returnVal); |
| returnVal = (String) adapter.invokeExact("foo", 42l, (String) null); |
| assertEquals("target", returnVal); |
| |
| // We're passing a non-null exception message here, which means the target will throw, |
| // which in turn means that the handler must be called for the next two invokes. |
| returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage"); |
| assertEquals("handler1", returnVal); |
| returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage"); |
| assertEquals("handler1", returnVal); |
| |
| handler = MethodHandles.lookup().findStatic(Main.class, |
| "testCatchException_handler2", |
| MethodType.methodType(String.class, new Class<?>[] { IllegalArgumentException.class, |
| String.class })); |
| adapter = MethodHandles.catchException(target, IllegalArgumentException.class, handler); |
| |
| returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage"); |
| assertEquals("handler2", returnVal); |
| returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage"); |
| assertEquals("handler2", returnVal); |
| |
| // Test that the type of the invoke doesn't matter. Here we call |
| // IllegalArgumentException.toString() on the exception that was thrown by |
| // the target. |
| handler = MethodHandles.lookup().findVirtual(IllegalArgumentException.class, |
| "toString", MethodType.methodType(String.class)); |
| adapter = MethodHandles.catchException(target, IllegalArgumentException.class, handler); |
| |
| returnVal = (String) adapter.invoke("foo", 42, "exceptionMessage"); |
| assertEquals("java.lang.IllegalArgumentException: exceptionMessage", returnVal); |
| returnVal = (String) adapter.invokeExact("foo", 42l, "exceptionMessage2"); |
| assertEquals("java.lang.IllegalArgumentException: exceptionMessage2", returnVal); |
| |
| // Check that asType works as expected. |
| adapter = MethodHandles.catchException(target, IllegalArgumentException.class, |
| handler); |
| adapter = adapter.asType(MethodType.methodType(String.class, |
| new Class<?>[] { String.class, int.class, String.class })); |
| returnVal = (String) adapter.invokeExact("foo", 42, "exceptionMessage"); |
| assertEquals("java.lang.IllegalArgumentException: exceptionMessage", returnVal); |
| } |
| |
| public static boolean testGuardWithTest_test(String arg1, long arg2) { |
| return "target".equals(arg1) && 42 == arg2; |
| } |
| |
| public static String testGuardWithTest_target(String arg1, long arg2, int arg3) { |
| System.out.println("target: " + arg1 + ", " + arg2 + ", " + arg3); |
| return "target"; |
| } |
| |
| public static String testGuardWithTest_fallback(String arg1, long arg2, int arg3) { |
| System.out.println("fallback: " + arg1 + ", " + arg2 + ", " + arg3); |
| return "fallback"; |
| } |
| |
| public static void testGuardWithTest() throws Throwable { |
| MethodHandle test = MethodHandles.lookup().findStatic(Main.class, |
| "testGuardWithTest_test", |
| MethodType.methodType(boolean.class, new Class<?>[] { String.class, long.class })); |
| |
| final MethodType type = MethodType.methodType(String.class, |
| new Class<?>[] { String.class, long.class, int.class }); |
| |
| final MethodHandle target = MethodHandles.lookup().findStatic(Main.class, |
| "testGuardWithTest_target", type); |
| final MethodHandle fallback = MethodHandles.lookup().findStatic(Main.class, |
| "testGuardWithTest_fallback", type); |
| |
| MethodHandle adapter = MethodHandles.guardWithTest(test, target, fallback); |
| |
| String returnVal = null; |
| |
| returnVal = (String) adapter.invoke("target", 42, 56); |
| assertEquals("target", returnVal); |
| returnVal = (String) adapter.invokeExact("target", 42l, 56); |
| assertEquals("target", returnVal); |
| |
| returnVal = (String) adapter.invoke("fallback", 42l, 56); |
| assertEquals("fallback", returnVal); |
| returnVal = (String) adapter.invokeExact("target", 42l, 56); |
| assertEquals("target", returnVal); |
| |
| // Check that asType works as expected. |
| adapter = adapter.asType(MethodType.methodType(String.class, |
| new Class<?>[] { String.class, int.class, int.class })); |
| returnVal = (String) adapter.invokeExact("target", 42, 56); |
| assertEquals("target", returnVal); |
| } |
| |
| public static void fail() { |
| System.out.println("FAIL"); |
| Thread.dumpStack(); |
| } |
| |
| public static void assertEquals(String s1, String s2) { |
| if (s1 == s2) { |
| return; |
| } |
| |
| if (s1 != null && s2 != null && s1.equals(s2)) { |
| return; |
| } |
| |
| throw new AssertionError("assertEquals s1: " + s1 + ", s2: " + s2); |
| } |
| } |
| |
| |