fix #IAXU8J

This commit is contained in:
Looly 2024-10-18 12:45:00 +08:00
parent 965518947e
commit dca5e5c0cb
3 changed files with 74 additions and 19 deletions

View File

@ -34,7 +34,7 @@ import java.util.Map;
/** /**
* 以类似反射的方式动态创建Lambda在性能上有一定优势同时避免每次调用Lambda时创建匿名内部类 * 以类似反射的方式动态创建Lambda在性能上有一定优势同时避免每次调用Lambda时创建匿名内部类
* *
* @author nasodaengineer * @author nasodaengineer
*/ */
public class LambdaFactory { public class LambdaFactory {
@ -58,14 +58,14 @@ public class LambdaFactory {
* </pre> * </pre>
* *
* @param functionInterfaceType 接受Lambda的函数式接口类型 * @param functionInterfaceType 接受Lambda的函数式接口类型
* @param methodClass 声明方法的类的类型 * @param declaringClass 声明方法的类的类型
* @param methodName 方法名称 * @param methodName 方法名称
* @param paramTypes 方法参数数组 * @param paramTypes 方法参数数组
* @param <F> Function类型 * @param <F> Function类型
* @return 接受Lambda的函数式接口对象 * @return 接受Lambda的函数式接口对象
*/ */
public static <F> F build(final Class<F> functionInterfaceType, final Class<?> methodClass, final String methodName, final Class<?>... paramTypes) { public static <F> F build(final Class<F> functionInterfaceType, final Class<?> declaringClass, final String methodName, final Class<?>... paramTypes) {
return build(functionInterfaceType, MethodUtil.getMethod(methodClass, methodName, paramTypes)); return build(functionInterfaceType, MethodUtil.getMethod(declaringClass, methodName, paramTypes), declaringClass);
} }
/** /**
@ -77,33 +77,50 @@ public class LambdaFactory {
* @param <F> Function类型 * @param <F> Function类型
* @return 接受Lambda的函数式接口对象 * @return 接受Lambda的函数式接口对象
*/ */
@SuppressWarnings("unchecked")
public static <F> F build(final Class<F> functionInterfaceType, final Executable executable) { public static <F> F build(final Class<F> functionInterfaceType, final Executable executable) {
return build(functionInterfaceType, executable, null);
}
/**
* 根据提供的方法或构造对象构建对应的Lambda函数<br>
* 调用函数相当于执行对应的方法或构造
*
* @param <F> Function类型
* @param functionInterfaceType 接受Lambda的函数式接口类型
* @param executable 方法对象支持构造器
* @param declaringClass {@link Executable}声明的类如果方法或构造定义在父类中此处用于指定子类
* @return 接受Lambda的函数式接口对象
*/
@SuppressWarnings("unchecked")
public static <F> F build(final Class<F> functionInterfaceType,
final Executable executable, final Class<?> declaringClass) {
Assert.notNull(functionInterfaceType); Assert.notNull(functionInterfaceType);
Assert.notNull(executable); Assert.notNull(executable);
final MutableEntry<Class<?>, Executable> cacheKey = new MutableEntry<>(functionInterfaceType, executable); final MutableEntry<Class<?>, Executable> cacheKey = new MutableEntry<>(functionInterfaceType, executable);
return (F) CACHE.computeIfAbsent(cacheKey, return (F) CACHE.computeIfAbsent(cacheKey,
key -> doBuildWithoutCache(functionInterfaceType, executable)); key -> doBuildWithoutCache(functionInterfaceType, executable, declaringClass));
} }
/** /**
* 根据提供的方法或构造对象构建对应的Lambda函数即通过Lambda函数代理方法或构造<br> * 根据提供的方法或构造对象构建对应的Lambda函数即通过Lambda函数代理方法或构造<br>
* 调用函数相当于执行对应的方法或构造 * 调用函数相当于执行对应的方法或构造
* *
* @param funcType 接受Lambda的函数式接口类型 * @param <F> Function类型
* @param executable 方法对象支持构造器 * @param funcType 接受Lambda的函数式接口类型
* @param <F> Function类型 * @param executable 方法对象支持构造器
* @param declaringClass {@link Executable}声明的类如果方法或构造定义在父类中此处用于指定子类
* @return 接受Lambda的函数式接口对象 * @return 接受Lambda的函数式接口对象
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static <F> F doBuildWithoutCache(final Class<F> funcType, final Executable executable) { private static <F> F doBuildWithoutCache(final Class<F> funcType,
final Executable executable, final Class<?> declaringClass) {
ReflectUtil.setAccessible(executable); ReflectUtil.setAccessible(executable);
// 获取Lambda函数 // 获取Lambda函数
final Method invokeMethod = LambdaUtil.getInvokeMethod(funcType); final Method invokeMethod = LambdaUtil.getInvokeMethod(funcType);
try { try {
return (F) metaFactory(funcType, invokeMethod, executable) return (F) metaFactory(funcType, invokeMethod, executable, declaringClass)
.getTarget().invoke(); .getTarget().invoke();
} catch (final Throwable e) { } catch (final Throwable e) {
throw new HutoolException(e); throw new HutoolException(e);
@ -117,14 +134,15 @@ public class LambdaFactory {
* https://gitee.com/dromara/hutool/issues/I96JIP * https://gitee.com/dromara/hutool/issues/I96JIP
* </p> * </p>
* *
* @param funcType 函数类型 * @param funcType 函数类型
* @param funcMethod 函数执行的方法 * @param funcMethod 函数执行的方法
* @param executable 被代理的方法或构造 * @param executable 被代理的方法或构造
* @param declaringClass {@link Executable}声明的类如果方法或构造定义在父类中此处用于指定子类
* @return {@link CallSite} * @return {@link CallSite}
* @throws LambdaConversionException 权限等异常 * @throws LambdaConversionException 权限等异常
*/ */
private static CallSite metaFactory(final Class<?> funcType, final Method funcMethod, 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()); final MethodHandles.Lookup caller = LookupUtil.lookup(executable.getDeclaringClass());
// 要实现的方法的名字 // 要实现的方法的名字
@ -145,7 +163,7 @@ public class LambdaFactory {
invokedType, invokedType,
samMethodType, samMethodType,
implMethodHandle, implMethodHandle,
MethodTypeUtil.methodType(executable), MethodTypeUtil.methodType(executable, declaringClass),
LambdaMetafactory.FLAG_SERIALIZABLE LambdaMetafactory.FLAG_SERIALIZABLE
); );
} }
@ -156,7 +174,7 @@ public class LambdaFactory {
invokedType, invokedType,
samMethodType, samMethodType,
implMethodHandle, implMethodHandle,
MethodTypeUtil.methodType(executable) MethodTypeUtil.methodType(executable, declaringClass)
); );
} }
} }

View File

@ -41,12 +41,31 @@ public class MethodTypeUtil {
* @return {@link MethodType} * @return {@link MethodType}
*/ */
public static MethodType methodType(final Executable executable) { public static MethodType methodType(final Executable executable) {
return methodType(executable, null);
}
/**
* 获取指定{@link Executable}{@link MethodType}<br>
* 此方法主要是读取方法或构造中的方法列表主要为
* <ul>
* <li>方法[返回类型, 参数1类型, 参数2类型, ...]</li>
* <li>构造[构造对应类类型, 参数1类型, 参数2类型, ...]</li>
* </ul>
*
* @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) { if (executable instanceof Method) {
final Method method = (Method) executable; final Method method = (Method) executable;
return MethodType.methodType(method.getReturnType(), method.getDeclaringClass(), method.getParameterTypes()); return MethodType.methodType(method.getReturnType(), declaringClass, method.getParameterTypes());
} else { } else {
final Constructor<?> constructor = (Constructor<?>) executable; final Constructor<?> constructor = (Constructor<?>) executable;
return MethodType.methodType(constructor.getDeclaringClass(), constructor.getParameterTypes()); return MethodType.methodType(declaringClass, constructor.getParameterTypes());
} }
} }
} }

View File

@ -348,4 +348,22 @@ public class LambdaUtilTest {
LambdaUtil.getInvokeMethod(LambdaUtilTest.class); LambdaUtil.getInvokeMethod(LambdaUtilTest.class);
}); });
} }
@SuppressWarnings("unchecked")
@Test
void issueIAXU8JTest() {
final SerFunction<Child, String> function1 = Child::getParentField;
final SerFunction<Child, String> 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 {
}
} }