diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaFactory.java b/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaFactory.java index 38401bc96..b3b534c90 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaFactory.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaFactory.java @@ -7,9 +7,12 @@ import cn.hutool.core.lang.mutable.MutableEntry; import cn.hutool.core.map.WeakConcurrentMap; import cn.hutool.core.reflect.LookupFactory; import cn.hutool.core.reflect.MethodUtil; +import cn.hutool.core.reflect.ReflectUtil; import java.io.Serializable; import java.lang.invoke.*; +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; @@ -31,7 +34,7 @@ public class LambdaFactory { throw new IllegalAccessException(); } - private static final Map, Method>, Object> CACHE = new WeakConcurrentMap<>(); + private static final Map, Executable>, Object> CACHE = new WeakConcurrentMap<>(); /** * 构建Lambda @@ -61,30 +64,37 @@ public class LambdaFactory { * 构建Lambda * * @param functionInterfaceType 接受Lambda的函数式接口类型 - * @param method 方法对象 + * @param executable 方法对象 + * @param Function类型 * @return 接受Lambda的函数式接口对象 - * @param Function类型 */ @SuppressWarnings("unchecked") - public static F build(final Class functionInterfaceType, final Method method) { + public static F build(final Class functionInterfaceType, final Executable executable) { Assert.notNull(functionInterfaceType); - Assert.notNull(method); - final MutableEntry, Method> cacheKey = new MutableEntry<>(functionInterfaceType, method); + Assert.notNull(executable); + final MutableEntry, Executable> cacheKey = new MutableEntry<>(functionInterfaceType, executable); return (F) CACHE.computeIfAbsent(cacheKey, key -> { final List abstractMethods = Arrays.stream(functionInterfaceType.getMethods()) .filter(m -> Modifier.isAbstract(m.getModifiers())) .collect(Collectors.toList()); Assert.equals(abstractMethods.size(), 1, "不支持非函数式接口"); - if (!method.isAccessible()) { - method.setAccessible(true); - } + ReflectUtil.setAccessible(executable); 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 MethodType invokedType = methodType(functionInterfaceType); final MethodType samMethodType = methodType(invokeMethod.getReturnType(), invokeMethod.getParameterTypes()); - final MethodHandle implMethod = Opt.ofTry(() -> caller.unreflect(method)).get(); - final MethodType insMethodType = methodType(method.getReturnType(), method.getDeclaringClass(), method.getParameterTypes()); + final MethodHandle implMethod; + final MethodType instantiatedMethodType; + if (executable instanceof Method) { + final Method method = (Method) executable; + implMethod = ((SerSupplier) () -> MethodHandles.lookup().unreflect(method)).get(); + instantiatedMethodType = MethodType.methodType(method.getReturnType(), method.getDeclaringClass(), method.getParameterTypes()); + } else { + final Constructor constructor = (Constructor) executable; + implMethod = ((SerSupplier) () -> MethodHandles.lookup().unreflectConstructor(constructor)).get(); + instantiatedMethodType = MethodType.methodType(constructor.getDeclaringClass(), constructor.getParameterTypes()); + } final boolean isSerializable = Serializable.class.isAssignableFrom(functionInterfaceType); try { final CallSite callSite = isSerializable ? @@ -94,7 +104,7 @@ public class LambdaFactory { invokedType, samMethodType, implMethod, - insMethodType, + instantiatedMethodType, FLAG_SERIALIZABLE ) : LambdaMetafactory.metafactory( @@ -103,7 +113,7 @@ public class LambdaFactory { invokedType, samMethodType, implMethod, - insMethodType + instantiatedMethodType ); //noinspection unchecked return (F) callSite.getTarget().invoke(); diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/func/LambdaFactoryTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/func/LambdaFactoryTest.java index 83f65ee41..db3f68ab3 100644 --- a/hutool-core/src/test/java/cn/hutool/core/lang/func/LambdaFactoryTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/lang/func/LambdaFactoryTest.java @@ -12,11 +12,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import java.lang.invoke.LambdaConversionException; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandleProxies; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; +import java.lang.invoke.*; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; @@ -24,6 +21,7 @@ import java.util.Comparator; import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; import java.util.function.Function; +import java.util.function.Supplier; /** * @author nasodaengineer @@ -160,6 +158,15 @@ public class LambdaFactoryTest { loop(count, tasks); } + @Test + public void testConstructor() { + Constructor constructor = ((SerSupplier>) Something.class::getConstructor).get(); + Supplier constructorLambda = LambdaFactory.build(Supplier.class, constructor); + // constructorLambda can be cache or transfer + Something something = constructorLambda.get(); + Assert.assertEquals(Something.class, something.getClass()); + } + /** *

hardCode 运行1次耗时 7600 NANOSECONDS *

lambda 运行1次耗时 12400 NANOSECONDS