152 lines
6.6 KiB
Java
152 lines
6.6 KiB
Java
package io.gitlab.jfronny.commons.unsafe.reflect;
|
|
|
|
import java.lang.invoke.LambdaMetafactory;
|
|
import java.lang.invoke.MethodHandle;
|
|
import java.lang.invoke.MethodHandles;
|
|
import java.lang.invoke.MethodType;
|
|
import java.util.function.*;
|
|
|
|
/**
|
|
* A class that wraps the LambdaMetafactory to more easily create lambdas from MethodHandles.
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
public class LambdaFactory {
|
|
private static final MethodHandles.Lookup LOOKUP_ROOT = MethodHandles.lookup();
|
|
|
|
/**
|
|
* Creates a private lookup for the given class.
|
|
* @param klazz the class to create the lookup for
|
|
* @return a lookup for the given class
|
|
* @throws IllegalAccessException if the lookup cannot be created
|
|
*/
|
|
public static MethodHandles.Lookup lookup(Class<?> klazz) throws IllegalAccessException {
|
|
return MethodHandles.privateLookupIn(klazz, LOOKUP_ROOT);
|
|
}
|
|
|
|
/**
|
|
* Creates a new Runnable from the given handle.
|
|
* @param lookup the lookup to use
|
|
* @param handle the handle to create the lambda from
|
|
* @return a new Runnable that calls the given handle
|
|
* @throws Throwable if the lambda cannot be created
|
|
*/
|
|
public static Runnable runnable(MethodHandles.Lookup lookup, MethodHandle handle) throws Throwable {
|
|
return (Runnable) LambdaMetafactory.metafactory(
|
|
lookup,
|
|
"run",
|
|
MethodType.methodType(Runnable.class),
|
|
MethodType.methodType(Void.TYPE),
|
|
handle,
|
|
MethodType.methodType(Void.TYPE)
|
|
).getTarget().invoke();
|
|
}
|
|
|
|
/**
|
|
* Creates a new Consumer from the given handle.
|
|
* @param lookup the lookup to use
|
|
* @param handle the handle to create the lambda from
|
|
* @param parameterType the type of the parameter
|
|
* @param <TIn> the type of the parameter
|
|
* @return a new Consumer that calls the given handle
|
|
* @throws Throwable if the lambda cannot be created
|
|
*/
|
|
public static <TIn> Consumer<TIn> consumer(MethodHandles.Lookup lookup, MethodHandle handle, Class<TIn> parameterType) throws Throwable {
|
|
return (Consumer<TIn>) LambdaMetafactory.metafactory(
|
|
lookup,
|
|
"accept",
|
|
MethodType.methodType(Consumer.class),
|
|
MethodType.methodType(Void.TYPE, Object.class),
|
|
handle,
|
|
MethodType.methodType(Void.TYPE, parameterType)
|
|
).getTarget().invoke();
|
|
}
|
|
|
|
/**
|
|
* Creates a new BiConsumer from the given handle.
|
|
* @param lookup the lookup to use
|
|
* @param handle the handle to create the lambda from
|
|
* @param parameterType1 the type of the first parameter
|
|
* @param parameterType2 the type of the second parameter
|
|
* @param <TIn1> the type of the first parameter
|
|
* @param <TIn2> the type of the second parameter
|
|
* @return a new BiConsumer that calls the given handle
|
|
* @throws Throwable if the lambda cannot be created
|
|
*/
|
|
public static <TIn1, TIn2> BiConsumer<TIn1, TIn2> consumer(MethodHandles.Lookup lookup, MethodHandle handle, Class<TIn1> parameterType1, Class<TIn2> parameterType2) throws Throwable {
|
|
return (BiConsumer<TIn1, TIn2>) LambdaMetafactory.metafactory(
|
|
lookup,
|
|
"accept",
|
|
MethodType.methodType(BiConsumer.class),
|
|
MethodType.methodType(Void.TYPE, Object.class, Object.class),
|
|
handle,
|
|
MethodType.methodType(Void.TYPE, parameterType1, parameterType2)
|
|
).getTarget().invoke();
|
|
}
|
|
|
|
/**
|
|
* Creates a new Supplier from the given handle.
|
|
* @param lookup the lookup to use
|
|
* @param handle the handle to create the lambda from
|
|
* @param returnType the return type of the supplier
|
|
* @param <TOut> the return type of the supplier
|
|
* @return a new Supplier that calls the given handle
|
|
* @throws Throwable if the lambda cannot be created
|
|
*/
|
|
public static <TOut> Supplier<TOut> supplier(MethodHandles.Lookup lookup, MethodHandle handle, Class<TOut> returnType) throws Throwable {
|
|
return (Supplier<TOut>) LambdaMetafactory.metafactory(
|
|
lookup,
|
|
"get",
|
|
MethodType.methodType(Supplier.class),
|
|
MethodType.methodType(Object.class),
|
|
handle,
|
|
MethodType.methodType(returnType)
|
|
).getTarget().invoke();
|
|
}
|
|
|
|
/**
|
|
* Creates a new Function from the given handle.
|
|
* @param lookup the lookup to use
|
|
* @param handle the handle to create the lambda from
|
|
* @param returnType the return type of the function
|
|
* @param parameterType the type of the parameter
|
|
* @param <TIn> the type of the parameter
|
|
* @param <TOut> the return type of the function
|
|
* @return a new Function that calls the given handle
|
|
* @throws Throwable if the lambda cannot be created
|
|
*/
|
|
public static <TIn, TOut> Function<TIn, TOut> function(MethodHandles.Lookup lookup, MethodHandle handle, Class<TOut> returnType, Class<TIn> parameterType) throws Throwable {
|
|
return (Function<TIn, TOut>) LambdaMetafactory.metafactory(
|
|
lookup,
|
|
"apply",
|
|
MethodType.methodType(Function.class),
|
|
MethodType.methodType(Object.class, Object.class),
|
|
handle,
|
|
MethodType.methodType(returnType, parameterType)
|
|
).getTarget().invoke();
|
|
}
|
|
|
|
/**
|
|
* Creates a new BiFunction from the given handle.
|
|
* @param lookup the lookup to use
|
|
* @param handle the handle to create the lambda from
|
|
* @param returnType the return type of the function
|
|
* @param parameterType1 the type of the first parameter
|
|
* @param parameterType2 the type of the second parameter
|
|
* @param <TIn1> the type of the first parameter
|
|
* @param <TIn2> the type of the second parameter
|
|
* @param <TOut> the return type of the function
|
|
* @return a new BiFunction that calls the given handle
|
|
* @throws Throwable if the lambda cannot be created
|
|
*/
|
|
public static <TIn1, TIn2, TOut> BiFunction<TIn1, TIn2, TOut> function(MethodHandles.Lookup lookup, MethodHandle handle, Class<TOut> returnType, Class<TIn1> parameterType1, Class<TIn2> parameterType2) throws Throwable {
|
|
return (BiFunction<TIn1, TIn2, TOut>) LambdaMetafactory.metafactory(
|
|
lookup,
|
|
"apply",
|
|
MethodType.methodType(BiFunction.class),
|
|
MethodType.methodType(Object.class, Object.class, Object.class),
|
|
handle,
|
|
MethodType.methodType(returnType, parameterType1, parameterType2)
|
|
).getTarget().invoke();
|
|
}
|
|
}
|