Skip to content

Instantly share code, notes, and snippets.

@sugar700
Created January 21, 2018 19:49
Show Gist options
  • Save sugar700/f0a0be72ef93690e2782a37c99961bd5 to your computer and use it in GitHub Desktop.
Save sugar700/f0a0be72ef93690e2782a37c99961bd5 to your computer and use it in GitHub Desktop.
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Objects;
import java.util.function.IntConsumer;
public class Lambdas {
private static <F, T> F createLambda(
Class<? extends F> output, T object, String methodName, Class<?>... inputTypes
) throws NoSuchMethodException {
MethodHandles.Lookup caller = MethodHandles.lookup();
Class<?> returnType = object.getClass().getMethod(methodName, inputTypes).getReturnType();
MethodType actualMethodType = MethodType.methodType(returnType, inputTypes);
Method foundInterfaceMethod = getInterfaceMethod(output.getMethods());
try {
@SuppressWarnings("unchecked")
F result = (F) LambdaMetafactory.metafactory(
caller,
foundInterfaceMethod.getName(),
MethodType.methodType(output, object.getClass()),
MethodType.methodType(foundInterfaceMethod.getReturnType(), foundInterfaceMethod.getParameterTypes()),
caller.findVirtual(object.getClass(), methodName, actualMethodType),
actualMethodType
).getTarget().invoke(object);
return result;
} catch (Throwable ex) {
throw new RuntimeException(ex);
}
}
private static Method getInterfaceMethod(Method[] interfaceMethods) {
Method foundInterfaceMethod = null;
for (Method interfaceMethod : interfaceMethods) {
if ((interfaceMethod.getModifiers() & Modifier.ABSTRACT) == Modifier.ABSTRACT) {
if (foundInterfaceMethod == null) {
foundInterfaceMethod = interfaceMethod;
} else {
throw new RuntimeException("Too many interface methods to implement");
}
}
}
return Objects.requireNonNull(foundInterfaceMethod);
}
public static void main(String[] args) throws NoSuchMethodException {
IntConsumer c = createLambda(IntConsumer.class, System.out, "println", int.class);
c.accept(42);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment