public static int invocationOpcode(int kind) throws InternalError { switch (kind) { case MethodHandleInfo.REF_invokeStatic: return INVOKESTATIC; case MethodHandleInfo.REF_newInvokeSpecial: return INVOKESPECIAL; case MethodHandleInfo.REF_invokeVirtual: return INVOKEVIRTUAL; case MethodHandleInfo.REF_invokeInterface: return INVOKEINTERFACE; case MethodHandleInfo.REF_invokeSpecial: return INVOKESPECIAL; default: throw new InternalError("Unexpected invocation kind: " + kind); } }
private static MethodHandle bind(VarHandle vh, MethodHandle mh, MethodType emt) { assertEquals(mh.type(), emt.insertParameterTypes(0, VarHandle.class), "MethodHandle type differs from access mode type"); MethodHandleInfo info = MethodHandles.lookup().revealDirect(mh); assertEquals(info.getMethodType(), emt, "MethodHandleInfo method type differs from access mode type"); return mh.bindTo(vh); }
@Test(dataProvider = "accessModesProvider", expectedExceptions = IllegalArgumentException.class) public void methodInvocationFromMethodInfo(VarHandle.AccessMode accessMode) throws Exception { VarHandle v = handle(); // Try a reflective invoke using a Method obtained from cracking // a MethodHandle MethodHandle mh = MethodHandles.lookup().unreflect( VarHandle.class.getMethod(accessMode.methodName(), Object[].class)); MethodHandleInfo info = MethodHandles.lookup().revealDirect(mh); Method im = info.reflectAs(Method.class, MethodHandles.lookup()); im.invoke(v, new Object[]{}); }
@Test(dataProvider = "accessModesProvider", expectedExceptions = IllegalArgumentException.class) public void reflectAsFromVarHandleInvoker(VarHandle.AccessMode accessMode) throws Exception { VarHandle v = handle(); MethodHandle mh = MethodHandles.varHandleInvoker( accessMode, v.accessModeType(accessMode)); MethodHandleInfo info = MethodHandles.lookup().revealDirect(mh); info.reflectAs(Method.class, MethodHandles.lookup()); }
@Test(dataProvider = "accessModesProvider", expectedExceptions = IllegalArgumentException.class) public void reflectAsFromFindVirtual(VarHandle.AccessMode accessMode) throws Exception { VarHandle v = handle(); MethodHandle mh = MethodHandles.publicLookup().findVirtual( VarHandle.class, accessMode.methodName(), v.accessModeType(accessMode)); MethodHandleInfo info = MethodHandles.lookup().revealDirect(mh); info.reflectAs(Method.class, MethodHandles.lookup()); }
/** * Get the only method in the class with the given return and parameter types * <p>Throws an exception if no fields are found, or if multiple fields are found.</p> * <p>Fields may have a subclass of the required type, and primitives are interchangeable with wrappers. Therefore passing Object accepts all fields.</p> * * @param clazz the type to find the method in * @param returnType the return type of the method to find * @param parameters the parameters of the method to find * @return the only method with the given return type and parameters * @throws IllegalArgumentException if there is more than one field with the given type * @throws IllegalArgumentException if not found * @throws NullPointerException if any args are null */ public static MethodHandle findMethodWithType(Class<?> clazz, Class returnType, Class<?>... parameters) { ImmutableList<MethodHandle> methods = findMethodsWithType(clazz, returnType, parameters); StringBuilder builder; switch (methods.size()) { case 1: return methods.get(0); case 0: throw new IllegalArgumentException(format( "Method in {} not found with type '({}){}'", clazz.getTypeName(), returnType, Arrays.stream(parameters) .map(Class::getTypeName) .collect(Collectors.joining(",")) )); default: throw new IllegalArgumentException(format( "Multiple methods with type '({}){}' found in {}: {}", returnType, Arrays.stream(parameters) .map(Class::getTypeName) .collect(Collectors.joining(",")), clazz.getTypeName(), methods.stream() .map(MethodHandles.lookup()::revealDirect) .map(MethodHandleInfo::getName) .collect(Collectors.joining(",", "[", "]")) )); } }
private MethodHandle implMethod(Lookup lookup, Class<?> implClass, MethodType implType) throws NoSuchMethodException, IllegalAccessException { switch (implMethodKind) { case MethodHandleInfo.REF_invokeInterface: case MethodHandleInfo.REF_invokeVirtual: return lookup.findVirtual(implClass, implMethodName, implType); case MethodHandleInfo.REF_invokeSpecial: return lookup.findSpecial(implClass, implMethodName, implType, implClass); case MethodHandleInfo.REF_invokeStatic: return lookup.findStatic(implClass, implMethodName, implType); default: throw new RuntimeException("Unsupported impl method kind " + implMethodKind); } }
@SuppressWarnings("unchecked") @Test public void testSerializeStaticNonCapturing() throws Exception { SerializedLambda serializedLambda = Lambdas.serializeLambda(splus); assertThat(serializedLambda.getCapturedArgCount(), equalTo(0)); LambdaSignature lambda = new LambdaSignature() .withCapturingClass(serializedLambda.getCapturingClass()) .withInstantiatedMethodType(serializedLambda.getInstantiatedMethodType()) .withFunctionalInterface(serializedLambda.getFunctionalInterfaceClass(), serializedLambda.getFunctionalInterfaceMethodName(), serializedLambda.getFunctionalInterfaceMethodSignature()) .withImplMethod(serializedLambda.getImplClass(), serializedLambda.getImplMethodKind(), serializedLambda.getImplMethodName(), serializedLambda.getImplMethodSignature()); assertThat(lambda.getCapturingClass(), equalTo("net/amygdalum/testrecorder/values/LambdaSignatureTest")); assertThat(lambda.getFunctionalInterfaceClass(), equalTo("java/util/function/BiFunction")); assertThat(lambda.getFunctionalInterfaceMethod().getDeclaringClass(), equalTo(BiFunction.class)); assertThat(lambda.getFunctionalInterfaceMethodName(), equalTo("apply")); assertThat(lambda.getFunctionalInterfaceMethodSignature(), equalTo("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;")); assertThat(lambda.getFunctionalInterfaceMethod().getName(), equalTo("apply")); assertThat(lambda.getFunctionalInterfaceMethod().getParameterTypes(), arrayContaining(Object.class, Object.class)); assertThat(lambda.getImplClass(), equalTo("net/amygdalum/testrecorder/values/LambdaSignatureTest")); assertThat(lambda.getImplMethod().getDeclaringClass(), equalTo(LambdaSignatureTest.class)); assertThat(lambda.getImplMethodKind(), equalTo(MethodHandleInfo.REF_invokeStatic)); assertThat(lambda.getImplMethodSignature(), equalTo("(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;")); assertThat(lambda.getImplMethod().getParameterTypes(), arrayContaining(Integer.class, Integer.class)); assertThat(lambda.getInstantiatedMethodType(), equalTo("(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;")); }
@SuppressWarnings("unchecked") @Test public void testSerializeStaticCapturing() throws Exception { SerializedLambda serializedLambda = Lambdas.serializeLambda(splusCapturing(42)); assertThat(serializedLambda.getCapturedArgCount(), equalTo(1)); assertThat(serializedLambda.getCapturedArg(0), equalTo(42)); LambdaSignature lambda = new LambdaSignature() .withCapturingClass(serializedLambda.getCapturingClass()) .withInstantiatedMethodType(serializedLambda.getInstantiatedMethodType()) .withFunctionalInterface(serializedLambda.getFunctionalInterfaceClass(), serializedLambda.getFunctionalInterfaceMethodName(), serializedLambda.getFunctionalInterfaceMethodSignature()) .withImplMethod(serializedLambda.getImplClass(), serializedLambda.getImplMethodKind(), serializedLambda.getImplMethodName(), serializedLambda.getImplMethodSignature()); assertThat(lambda.getCapturingClass(), equalTo("net/amygdalum/testrecorder/values/LambdaSignatureTest")); assertThat(lambda.getFunctionalInterfaceClass(), equalTo("java/util/function/Function")); assertThat(lambda.getFunctionalInterfaceMethod().getDeclaringClass(), equalTo(Function.class)); assertThat(lambda.getFunctionalInterfaceMethodName(), equalTo("apply")); assertThat(lambda.getFunctionalInterfaceMethodSignature(), equalTo("(Ljava/lang/Object;)Ljava/lang/Object;")); assertThat(lambda.getFunctionalInterfaceMethod().getName(), equalTo("apply")); assertThat(lambda.getFunctionalInterfaceMethod().getParameterTypes(), arrayContaining(Object.class)); assertThat(lambda.getImplClass(), equalTo("net/amygdalum/testrecorder/values/LambdaSignatureTest")); assertThat(lambda.getImplMethodKind(), equalTo(MethodHandleInfo.REF_invokeStatic)); assertThat(lambda.getImplMethodSignature(), equalTo("(ILjava/lang/Integer;)Ljava/lang/Integer;")); assertThat(lambda.getImplMethod().getParameterTypes(), arrayContaining(int.class, Integer.class)); assertThat(lambda.getInstantiatedMethodType(), equalTo("(Ljava/lang/Integer;)Ljava/lang/Integer;")); }
@SuppressWarnings("unchecked") @Test public void testSerializeInstanceCapturing() throws Exception { SerializedLambda serializedLambda = Lambdas.serializeLambda(this.splusInstanceCapturing()); assertThat(serializedLambda.getCapturedArgCount(), equalTo(1)); assertThat(serializedLambda.getCapturedArg(0), equalTo(this)); LambdaSignature lambda = new LambdaSignature() .withCapturingClass(serializedLambda.getCapturingClass()) .withInstantiatedMethodType(serializedLambda.getInstantiatedMethodType()) .withFunctionalInterface(serializedLambda.getFunctionalInterfaceClass(), serializedLambda.getFunctionalInterfaceMethodName(), serializedLambda.getFunctionalInterfaceMethodSignature()) .withImplMethod(serializedLambda.getImplClass(), serializedLambda.getImplMethodKind(), serializedLambda.getImplMethodName(), serializedLambda.getImplMethodSignature()); assertThat(lambda.getCapturingClass(), equalTo("net/amygdalum/testrecorder/values/LambdaSignatureTest")); assertThat(lambda.getFunctionalInterfaceClass(), equalTo("java/util/function/Function")); assertThat(lambda.getFunctionalInterfaceMethod().getDeclaringClass(), equalTo(Function.class)); assertThat(lambda.getFunctionalInterfaceMethodName(), equalTo("apply")); assertThat(lambda.getFunctionalInterfaceMethodSignature(), equalTo("(Ljava/lang/Object;)Ljava/lang/Object;")); assertThat(lambda.getFunctionalInterfaceMethod().getName(), equalTo("apply")); assertThat(lambda.getFunctionalInterfaceMethod().getParameterTypes(), arrayContaining(Object.class)); assertThat(lambda.getImplClass(), equalTo("net/amygdalum/testrecorder/values/LambdaSignatureTest")); assertThat(lambda.getImplMethodKind(), equalTo(MethodHandleInfo.REF_invokeSpecial)); assertThat(lambda.getImplMethodSignature(), equalTo("(Ljava/lang/Integer;)Ljava/lang/Integer;")); assertThat(lambda.getImplMethod().getParameterTypes(), arrayContaining(Integer.class)); assertThat(lambda.getInstantiatedMethodType(), equalTo("(Ljava/lang/Integer;)Ljava/lang/Integer;")); }
public MethodHandleInfo virtualInfo(Class<?> target, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { return lookup.revealDirect(virtualHandle(target, name, type)); }
public MethodHandleInfo virtualInfo(Class<?> target, Method called) throws NoSuchMethodException, IllegalAccessException { return virtualInfo(target, called.getName(), Methods.methodType(called)); }
private boolean isInstanceMethod() { return implMethodKind != MethodHandleInfo.REF_invokeStatic; }
private MethodHandleInfo info() { if (info == null) { info = MethodHandles.publicLookup().revealDirect(handle); } return info; }
/** * Validates implementation method kind (for invoke virtual and invoke * interface) * * @param lambda * @return <code>boolean</code> validation result */ private static boolean validateMethodKind(LambdaInfo lambda) { boolean valid; int kind = lambda.getImplMethodKind(); valid = ((kind == MethodHandleInfo.REF_invokeVirtual) || (kind == MethodHandleInfo.REF_invokeInterface)); return valid; }