From dca5e5c0cb6f7a744c29a76ac6df7f75725ea2a8 Mon Sep 17 00:00:00 2001
From: Looly
Date: Fri, 18 Oct 2024 12:45:00 +0800
Subject: [PATCH] fix #IAXU8J
---
.../hutool/core/func/LambdaFactory.java | 52 +++++++++++++------
.../core/reflect/method/MethodTypeUtil.java | 23 +++++++-
.../hutool/core/func/LambdaUtilTest.java | 18 +++++++
3 files changed, 74 insertions(+), 19 deletions(-)
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/func/LambdaFactory.java b/hutool-core/src/main/java/org/dromara/hutool/core/func/LambdaFactory.java
index 4ae2853f9..cb28d25f0 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/func/LambdaFactory.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/func/LambdaFactory.java
@@ -34,7 +34,7 @@ import java.util.Map;
/**
* 以类似反射的方式动态创建Lambda,在性能上有一定优势,同时避免每次调用Lambda时创建匿名内部类
*
- * @author nasodaengineer
+ * @author nasodaengineer
*/
public class LambdaFactory {
@@ -58,14 +58,14 @@ public class LambdaFactory {
*
*
* @param functionInterfaceType 接受Lambda的函数式接口类型
- * @param methodClass 声明方法的类的类型
+ * @param declaringClass 声明方法的类的类型
* @param methodName 方法名称
* @param paramTypes 方法参数数组
* @param Function类型
* @return 接受Lambda的函数式接口对象
*/
- public static F build(final Class functionInterfaceType, final Class> methodClass, final String methodName, final Class>... paramTypes) {
- return build(functionInterfaceType, MethodUtil.getMethod(methodClass, methodName, paramTypes));
+ public static F build(final Class functionInterfaceType, final Class> declaringClass, final String methodName, final Class>... paramTypes) {
+ return build(functionInterfaceType, MethodUtil.getMethod(declaringClass, methodName, paramTypes), declaringClass);
}
/**
@@ -77,33 +77,50 @@ public class LambdaFactory {
* @param Function类型
* @return 接受Lambda的函数式接口对象
*/
- @SuppressWarnings("unchecked")
public static F build(final Class functionInterfaceType, final Executable executable) {
+ return build(functionInterfaceType, executable, null);
+ }
+
+ /**
+ * 根据提供的方法或构造对象,构建对应的Lambda函数
+ * 调用函数相当于执行对应的方法或构造
+ *
+ * @param Function类型
+ * @param functionInterfaceType 接受Lambda的函数式接口类型
+ * @param executable 方法对象,支持构造器
+ * @param declaringClass {@link Executable}声明的类,如果方法或构造定义在父类中,此处用于指定子类
+ * @return 接受Lambda的函数式接口对象
+ */
+ @SuppressWarnings("unchecked")
+ public static F build(final Class functionInterfaceType,
+ final Executable executable, final Class> declaringClass) {
Assert.notNull(functionInterfaceType);
Assert.notNull(executable);
final MutableEntry, Executable> cacheKey = new MutableEntry<>(functionInterfaceType, executable);
return (F) CACHE.computeIfAbsent(cacheKey,
- key -> doBuildWithoutCache(functionInterfaceType, executable));
+ key -> doBuildWithoutCache(functionInterfaceType, executable, declaringClass));
}
/**
* 根据提供的方法或构造对象,构建对应的Lambda函数,即通过Lambda函数代理方法或构造
* 调用函数相当于执行对应的方法或构造
*
- * @param funcType 接受Lambda的函数式接口类型
- * @param executable 方法对象,支持构造器
- * @param Function类型
+ * @param Function类型
+ * @param funcType 接受Lambda的函数式接口类型
+ * @param executable 方法对象,支持构造器
+ * @param declaringClass {@link Executable}声明的类,如果方法或构造定义在父类中,此处用于指定子类
* @return 接受Lambda的函数式接口对象
*/
@SuppressWarnings("unchecked")
- private static F doBuildWithoutCache(final Class funcType, final Executable executable) {
+ private static F doBuildWithoutCache(final Class funcType,
+ final Executable executable, final Class> declaringClass) {
ReflectUtil.setAccessible(executable);
// 获取Lambda函数
final Method invokeMethod = LambdaUtil.getInvokeMethod(funcType);
try {
- return (F) metaFactory(funcType, invokeMethod, executable)
+ return (F) metaFactory(funcType, invokeMethod, executable, declaringClass)
.getTarget().invoke();
} catch (final Throwable e) {
throw new HutoolException(e);
@@ -117,14 +134,15 @@ public class LambdaFactory {
* 见:https://gitee.com/dromara/hutool/issues/I96JIP
*
*
- * @param funcType 函数类型
- * @param funcMethod 函数执行的方法
- * @param executable 被代理的方法或构造
+ * @param funcType 函数类型
+ * @param funcMethod 函数执行的方法
+ * @param executable 被代理的方法或构造
+ * @param declaringClass {@link Executable}声明的类,如果方法或构造定义在父类中,此处用于指定子类
* @return {@link CallSite}
* @throws LambdaConversionException 权限等异常
*/
private static CallSite metaFactory(final Class> funcType, final Method funcMethod,
- final Executable executable) throws LambdaConversionException {
+ final Executable executable, final Class> declaringClass) throws LambdaConversionException {
// 查找上下文与调用者的访问权限
final MethodHandles.Lookup caller = LookupUtil.lookup(executable.getDeclaringClass());
// 要实现的方法的名字
@@ -145,7 +163,7 @@ public class LambdaFactory {
invokedType,
samMethodType,
implMethodHandle,
- MethodTypeUtil.methodType(executable),
+ MethodTypeUtil.methodType(executable, declaringClass),
LambdaMetafactory.FLAG_SERIALIZABLE
);
}
@@ -156,7 +174,7 @@ public class LambdaFactory {
invokedType,
samMethodType,
implMethodHandle,
- MethodTypeUtil.methodType(executable)
+ MethodTypeUtil.methodType(executable, declaringClass)
);
}
}
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/method/MethodTypeUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/method/MethodTypeUtil.java
index ab2d12df0..60bb87b53 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/method/MethodTypeUtil.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/method/MethodTypeUtil.java
@@ -41,12 +41,31 @@ public class MethodTypeUtil {
* @return {@link MethodType}
*/
public static MethodType methodType(final Executable executable) {
+ return methodType(executable, null);
+ }
+
+ /**
+ * 获取指定{@link Executable}的{@link MethodType}
+ * 此方法主要是读取方法或构造中的方法列表,主要为:
+ *
+ * - 方法:[返回类型, 参数1类型, 参数2类型, ...]
+ * - 构造:[构造对应类类型, 参数1类型, 参数2类型, ...]
+ *
+ *
+ * @param executable 方法或构造
+ * @param declaringClass 方法或构造对应的类,用于获取其声明的参数类型,如果为{@code null},则使用{@link Executable#getDeclaringClass()}
+ * @return {@link MethodType}
+ */
+ public static MethodType methodType(final Executable executable, Class> declaringClass) {
+ if (null == declaringClass) {
+ declaringClass = executable.getDeclaringClass();
+ }
if (executable instanceof Method) {
final Method method = (Method) executable;
- return MethodType.methodType(method.getReturnType(), method.getDeclaringClass(), method.getParameterTypes());
+ return MethodType.methodType(method.getReturnType(), declaringClass, method.getParameterTypes());
} else {
final Constructor> constructor = (Constructor>) executable;
- return MethodType.methodType(constructor.getDeclaringClass(), constructor.getParameterTypes());
+ return MethodType.methodType(declaringClass, constructor.getParameterTypes());
}
}
}
diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/func/LambdaUtilTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/func/LambdaUtilTest.java
index 3e996d341..64b09a2a8 100644
--- a/hutool-core/src/test/java/org/dromara/hutool/core/func/LambdaUtilTest.java
+++ b/hutool-core/src/test/java/org/dromara/hutool/core/func/LambdaUtilTest.java
@@ -348,4 +348,22 @@ public class LambdaUtilTest {
LambdaUtil.getInvokeMethod(LambdaUtilTest.class);
});
}
+
+ @SuppressWarnings("unchecked")
+ @Test
+ void issueIAXU8JTest() {
+ final SerFunction function1 = Child::getParentField;
+ final SerFunction function2 = LambdaUtil.build(SerFunction.class, Child.class, "getParentField");
+
+ Assertions.assertEquals(LambdaUtil.getRealClass(function1), LambdaUtil.getRealClass(function2));
+ }
+
+ @Data
+ static
+ class Parent {
+ private String parentField;
+ }
+
+ static class Child extends Parent {
+ }
}