diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaInfo.java b/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaInfo.java index 3fcf9ffa5..7a5eca69d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaInfo.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaInfo.java @@ -17,7 +17,7 @@ import java.lang.reflect.Type; */ public class LambdaInfo { - private Type instantiatedType; + private final Type[] instantiatedTypes; private final Type[] parameterTypes; private final Type returnType; private final String name; @@ -41,15 +41,21 @@ public class LambdaInfo { } int index = lambda.getInstantiatedMethodType().indexOf(";)"); if (index > -1) { - this.instantiatedType = ClassLoaderUtil.loadClass(StrUtil.sub(lambda.getInstantiatedMethodType(), 2, index)); + String[] instantiatedTypeNames = StrUtil.sub(lambda.getInstantiatedMethodType(), 2, index).split(";L"); + this.instantiatedTypes = new Type[instantiatedTypeNames.length]; + for (int i = 0; i < instantiatedTypeNames.length; i++) { + this.instantiatedTypes[i] = ClassLoaderUtil.loadClass(instantiatedTypeNames[i]); + } + } else { + instantiatedTypes = new Type[0]; } this.clazz = (Class) FieldUtil.getFieldValue(executable, "clazz"); this.executable = executable; this.lambda = lambda; } - public Type getInstantiatedType() { - return instantiatedType; + public Type[] getInstantiatedTypes() { + return instantiatedTypes; } public Type[] getParameterTypes() { diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java b/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java index b6a7726f7..fc28793f7 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java @@ -60,7 +60,7 @@ public class LambdaUtil { @SuppressWarnings("unchecked") public static Class getRealClass(final Serializable func) { LambdaInfo lambdaInfo = resolve(func); - return (Class) Opt.of(lambdaInfo).map(LambdaInfo::getInstantiatedType).orElseGet(lambdaInfo::getClazz); + return (Class) Opt.of(lambdaInfo).map(LambdaInfo::getInstantiatedTypes).filter(types -> types.length != 0).map(types -> types[types.length - 1]).orElseGet(lambdaInfo::getClazz); } /** @@ -131,12 +131,11 @@ public class LambdaUtil { //region Private methods /** - * 解析lambda表达式,加了缓存。 - * 该缓存可能会在任意不定的时间被清除。 + * 解析lambda表达式,没加缓存 * *

* 通过反射调用实现序列化接口函数对象的writeReplace方法,从而拿到{@link SerializedLambda}
- * 该对象中包含了lambda表达式的所有信息。 + * 该对象中包含了lambda表达式的大部分信息。 *

* * @param func 需要解析的 lambda 对象 @@ -147,11 +146,11 @@ public class LambdaUtil { return (SerializedLambda) func; } if (func instanceof Proxy) { - throw new UtilException("not support proxy, just for now"); + throw new IllegalArgumentException("not support proxy, just for now"); } final Class clazz = func.getClass(); if (!clazz.isSynthetic()) { - throw new UtilException("Not a lambda expression: " + clazz.getName()); + throw new IllegalArgumentException("Not a lambda expression: " + clazz.getName()); } final Object serLambda = MethodUtil.invoke(func, "writeReplace"); if (Objects.nonNull(serLambda) && serLambda instanceof SerializedLambda) { diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/func/LambdaUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/func/LambdaUtilTest.java index b3cee7aac..37fb1833e 100644 --- a/hutool-core/src/test/java/cn/hutool/core/lang/func/LambdaUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/lang/func/LambdaUtilTest.java @@ -6,7 +6,9 @@ import lombok.EqualsAndHashCode; import org.junit.Assert; import org.junit.Test; +import java.io.Serializable; import java.lang.reflect.Array; +import java.util.Objects; import java.util.stream.Stream; @SuppressWarnings("unchecked") @@ -14,13 +16,15 @@ public class LambdaUtilTest { @Test public void getMethodNameTest() { - final String methodName = LambdaUtil.getMethodName(MyTeacher::getAge); + Func1 lambda = MyTeacher::getAge; + final String methodName = LambdaUtil.getMethodName(lambda); Assert.assertEquals("getAge", methodName); } @Test public void getFieldNameTest() { - final String fieldName = LambdaUtil.getFieldName(MyTeacher::getAge); + Func1 lambda = MyTeacher::getAge; + final String fieldName = LambdaUtil.getFieldName(lambda); Assert.assertEquals("age", fieldName); } @@ -40,20 +44,45 @@ public class LambdaUtilTest { Assert.assertEquals(MyTeacher.class, ((Class) lambdaInfo.getReturnType()).getComponentType()); }, () -> { // 引用静态方法 - Func0 noArgsStaticMethod = MyTeacher::takeAge; - LambdaInfo lambdaInfo = LambdaUtil.resolve(noArgsStaticMethod); + Func0 lambda = MyTeacher::takeAge; + LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda); + Assert.assertEquals(0, lambdaInfo.getParameterTypes().length); Assert.assertEquals(String.class, lambdaInfo.getReturnType()); }, () -> { // 引用特定对象的实例方法 - Func0 instantiated = new MyTeacher()::getAge; - LambdaInfo lambdaInfo = LambdaUtil.resolve(instantiated); + Func0 lambda = new MyTeacher()::getAge; + LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda); + Assert.assertEquals(0, lambdaInfo.getParameterTypes().length); Assert.assertEquals(String.class, lambdaInfo.getReturnType()); }, () -> { // 引用特定类型的任意对象的实例方法 - Func1 annoInstantiated = MyTeacher::getAge; - LambdaInfo lambdaInfo = LambdaUtil.resolve(annoInstantiated); + Func1 lambda = MyTeacher::getAge; + LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda); + Assert.assertEquals(0, lambdaInfo.getParameterTypes().length); Assert.assertEquals(String.class, lambdaInfo.getReturnType()); + }, () -> { + // 最最重要的!!! + Character character = '0'; + Integer integer = 0; + SerThiCons lambda = (obj, bool, str) -> { + Objects.nonNull(character); + Objects.nonNull(integer); + }; + LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda); + // 获取闭包使用的参数类型 + Assert.assertEquals(Character.class, lambdaInfo.getParameterTypes()[0]); + Assert.assertEquals(Integer.class, lambdaInfo.getParameterTypes()[1]); + // 最后几个是原有lambda的参数类型 + Assert.assertEquals(Object.class, lambdaInfo.getParameterTypes()[2]); + Assert.assertEquals(Boolean.class, lambdaInfo.getParameterTypes()[3]); + Assert.assertEquals(String.class, lambdaInfo.getParameterTypes()[4]); + + Assert.assertEquals(void.class, lambdaInfo.getReturnType()); }).forEach(Runnable::run); + + } + + interface SerThiCons extends Consumer3, Serializable { } @Test