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 { + } }