mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
!960 [enhancement] 使LambdaFactory.build支持构造器
Merge pull request !960 from 阿超/v6-dev
This commit is contained in:
commit
d9cd597256
@ -7,9 +7,12 @@ import cn.hutool.core.lang.mutable.MutableEntry;
|
|||||||
import cn.hutool.core.map.WeakConcurrentMap;
|
import cn.hutool.core.map.WeakConcurrentMap;
|
||||||
import cn.hutool.core.reflect.LookupFactory;
|
import cn.hutool.core.reflect.LookupFactory;
|
||||||
import cn.hutool.core.reflect.MethodUtil;
|
import cn.hutool.core.reflect.MethodUtil;
|
||||||
|
import cn.hutool.core.reflect.ReflectUtil;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.lang.invoke.*;
|
import java.lang.invoke.*;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Executable;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -31,7 +34,7 @@ public class LambdaFactory {
|
|||||||
throw new IllegalAccessException();
|
throw new IllegalAccessException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Map<MutableEntry<Class<?>, Method>, Object> CACHE = new WeakConcurrentMap<>();
|
private static final Map<MutableEntry<Class<?>, Executable>, Object> CACHE = new WeakConcurrentMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建Lambda
|
* 构建Lambda
|
||||||
@ -61,30 +64,37 @@ public class LambdaFactory {
|
|||||||
* 构建Lambda
|
* 构建Lambda
|
||||||
*
|
*
|
||||||
* @param functionInterfaceType 接受Lambda的函数式接口类型
|
* @param functionInterfaceType 接受Lambda的函数式接口类型
|
||||||
* @param method 方法对象
|
* @param executable 方法对象,支持构造器
|
||||||
|
* @param <F> Function类型
|
||||||
* @return 接受Lambda的函数式接口对象
|
* @return 接受Lambda的函数式接口对象
|
||||||
* @param <F> Function类型
|
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <F> F build(final Class<F> functionInterfaceType, final Method method) {
|
public static <F> F build(final Class<F> functionInterfaceType, final Executable executable) {
|
||||||
Assert.notNull(functionInterfaceType);
|
Assert.notNull(functionInterfaceType);
|
||||||
Assert.notNull(method);
|
Assert.notNull(executable);
|
||||||
final MutableEntry<Class<?>, Method> cacheKey = new MutableEntry<>(functionInterfaceType, method);
|
final MutableEntry<Class<?>, Executable> cacheKey = new MutableEntry<>(functionInterfaceType, executable);
|
||||||
return (F) CACHE.computeIfAbsent(cacheKey, key -> {
|
return (F) CACHE.computeIfAbsent(cacheKey, key -> {
|
||||||
final List<Method> abstractMethods = Arrays.stream(functionInterfaceType.getMethods())
|
final List<Method> abstractMethods = Arrays.stream(functionInterfaceType.getMethods())
|
||||||
.filter(m -> Modifier.isAbstract(m.getModifiers()))
|
.filter(m -> Modifier.isAbstract(m.getModifiers()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
Assert.equals(abstractMethods.size(), 1, "不支持非函数式接口");
|
Assert.equals(abstractMethods.size(), 1, "不支持非函数式接口");
|
||||||
if (!method.isAccessible()) {
|
ReflectUtil.setAccessible(executable);
|
||||||
method.setAccessible(true);
|
|
||||||
}
|
|
||||||
final Method invokeMethod = abstractMethods.get(0);
|
final Method invokeMethod = abstractMethods.get(0);
|
||||||
final MethodHandles.Lookup caller = LookupFactory.lookup(method.getDeclaringClass());
|
final MethodHandles.Lookup caller = LookupFactory.lookup(executable.getDeclaringClass());
|
||||||
final String invokeName = invokeMethod.getName();
|
final String invokeName = invokeMethod.getName();
|
||||||
final MethodType invokedType = methodType(functionInterfaceType);
|
final MethodType invokedType = methodType(functionInterfaceType);
|
||||||
final MethodType samMethodType = methodType(invokeMethod.getReturnType(), invokeMethod.getParameterTypes());
|
final MethodType samMethodType = methodType(invokeMethod.getReturnType(), invokeMethod.getParameterTypes());
|
||||||
final MethodHandle implMethod = Opt.ofTry(() -> caller.unreflect(method)).get();
|
final MethodHandle implMethod;
|
||||||
final MethodType insMethodType = methodType(method.getReturnType(), method.getDeclaringClass(), method.getParameterTypes());
|
final MethodType instantiatedMethodType;
|
||||||
|
if (executable instanceof Method) {
|
||||||
|
final Method method = (Method) executable;
|
||||||
|
implMethod = ((SerSupplier<MethodHandle>) () -> MethodHandles.lookup().unreflect(method)).get();
|
||||||
|
instantiatedMethodType = MethodType.methodType(method.getReturnType(), method.getDeclaringClass(), method.getParameterTypes());
|
||||||
|
} else {
|
||||||
|
final Constructor<?> constructor = (Constructor<?>) executable;
|
||||||
|
implMethod = ((SerSupplier<MethodHandle>) () -> MethodHandles.lookup().unreflectConstructor(constructor)).get();
|
||||||
|
instantiatedMethodType = MethodType.methodType(constructor.getDeclaringClass(), constructor.getParameterTypes());
|
||||||
|
}
|
||||||
final boolean isSerializable = Serializable.class.isAssignableFrom(functionInterfaceType);
|
final boolean isSerializable = Serializable.class.isAssignableFrom(functionInterfaceType);
|
||||||
try {
|
try {
|
||||||
final CallSite callSite = isSerializable ?
|
final CallSite callSite = isSerializable ?
|
||||||
@ -94,7 +104,7 @@ public class LambdaFactory {
|
|||||||
invokedType,
|
invokedType,
|
||||||
samMethodType,
|
samMethodType,
|
||||||
implMethod,
|
implMethod,
|
||||||
insMethodType,
|
instantiatedMethodType,
|
||||||
FLAG_SERIALIZABLE
|
FLAG_SERIALIZABLE
|
||||||
) :
|
) :
|
||||||
LambdaMetafactory.metafactory(
|
LambdaMetafactory.metafactory(
|
||||||
@ -103,7 +113,7 @@ public class LambdaFactory {
|
|||||||
invokedType,
|
invokedType,
|
||||||
samMethodType,
|
samMethodType,
|
||||||
implMethod,
|
implMethod,
|
||||||
insMethodType
|
instantiatedMethodType
|
||||||
);
|
);
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
return (F) callSite.getTarget().invoke();
|
return (F) callSite.getTarget().invoke();
|
||||||
|
@ -12,11 +12,8 @@ import org.junit.Test;
|
|||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.Parameterized;
|
import org.junit.runners.Parameterized;
|
||||||
|
|
||||||
import java.lang.invoke.LambdaConversionException;
|
import java.lang.invoke.*;
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.invoke.MethodHandleProxies;
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.lang.invoke.MethodType;
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -24,6 +21,7 @@ import java.util.Comparator;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author nasodaengineer
|
* @author nasodaengineer
|
||||||
@ -160,6 +158,15 @@ public class LambdaFactoryTest {
|
|||||||
loop(count, tasks);
|
loop(count, tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConstructor() {
|
||||||
|
Constructor<Something> constructor = ((SerSupplier<Constructor<Something>>) Something.class::getConstructor).get();
|
||||||
|
Supplier<Something> constructorLambda = LambdaFactory.build(Supplier.class, constructor);
|
||||||
|
// constructorLambda can be cache or transfer
|
||||||
|
Something something = constructorLambda.get();
|
||||||
|
Assert.assertEquals(Something.class, something.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>hardCode 运行1次耗时 7600 NANOSECONDS
|
* <p>hardCode 运行1次耗时 7600 NANOSECONDS
|
||||||
* <p>lambda 运行1次耗时 12400 NANOSECONDS
|
* <p>lambda 运行1次耗时 12400 NANOSECONDS
|
||||||
|
Loading…
x
Reference in New Issue
Block a user