This commit is contained in:
Looly 2023-03-25 07:26:59 +08:00
parent dacb489c12
commit af1ac9c121
3 changed files with 47 additions and 19 deletions

View File

@ -4,10 +4,7 @@ import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.mutable.MutableEntry; import cn.hutool.core.lang.mutable.MutableEntry;
import cn.hutool.core.map.WeakConcurrentMap; import cn.hutool.core.map.WeakConcurrentMap;
import cn.hutool.core.reflect.LookupFactory; import cn.hutool.core.reflect.*;
import cn.hutool.core.reflect.MethodUtil;
import cn.hutool.core.reflect.ModifierUtil;
import cn.hutool.core.reflect.ReflectUtil;
import java.io.Serializable; import java.io.Serializable;
import java.lang.invoke.*; import java.lang.invoke.*;
@ -80,23 +77,23 @@ public class LambdaFactory {
.collect(Collectors.toList()); .collect(Collectors.toList());
Assert.equals(abstractMethods.size(), 1, "不支持非函数式接口"); Assert.equals(abstractMethods.size(), 1, "不支持非函数式接口");
ReflectUtil.setAccessible(executable); ReflectUtil.setAccessible(executable);
final MethodHandle methodHandle = MethodHandleUtil.unreflect(executable);
final MethodType instantiatedMethodType;
if (executable instanceof Method) {
final Method method = (Method) executable;
instantiatedMethodType = MethodType.methodType(method.getReturnType(), method.getDeclaringClass(), method.getParameterTypes());
} else {
final Constructor<?> constructor = (Constructor<?>) executable;
instantiatedMethodType = MethodType.methodType(constructor.getDeclaringClass(), constructor.getParameterTypes());
}
final boolean isSerializable = Serializable.class.isAssignableFrom(functionInterfaceType);
final Method invokeMethod = abstractMethods.get(0); final Method invokeMethod = abstractMethods.get(0);
final MethodHandles.Lookup caller = LookupFactory.lookup(executable.getDeclaringClass()); final MethodHandles.Lookup caller = LookupFactory.lookup(executable.getDeclaringClass());
final String invokeName = invokeMethod.getName(); final String invokeName = invokeMethod.getName();
final MethodType invokedType = methodType(functionInterfaceType); final MethodType invokedType = methodType(functionInterfaceType);
final MethodType samMethodType = methodType(invokeMethod.getReturnType(), invokeMethod.getParameterTypes()); final MethodType samMethodType = methodType(invokeMethod.getReturnType(), invokeMethod.getParameterTypes());
final MethodHandle implMethod;
final MethodType instantiatedMethodType;
if (executable instanceof Method) {
final Method method = (Method) executable;
implMethod = ((SerSupplier<MethodHandle>) () -> MethodHandles.lookup().unreflect(method)).get();
instantiatedMethodType = MethodType.methodType(method.getReturnType(), method.getDeclaringClass(), method.getParameterTypes());
} else {
final Constructor<?> constructor = (Constructor<?>) executable;
implMethod = ((SerSupplier<MethodHandle>) () -> MethodHandles.lookup().unreflectConstructor(constructor)).get();
instantiatedMethodType = MethodType.methodType(constructor.getDeclaringClass(), constructor.getParameterTypes());
}
final boolean isSerializable = Serializable.class.isAssignableFrom(functionInterfaceType);
try { try {
final CallSite callSite = isSerializable ? final CallSite callSite = isSerializable ?
LambdaMetafactory.altMetafactory( LambdaMetafactory.altMetafactory(
@ -104,7 +101,7 @@ public class LambdaFactory {
invokeName, invokeName,
invokedType, invokedType,
samMethodType, samMethodType,
implMethod, methodHandle,
instantiatedMethodType, instantiatedMethodType,
FLAG_SERIALIZABLE FLAG_SERIALIZABLE
) : ) :
@ -113,7 +110,7 @@ public class LambdaFactory {
invokeName, invokeName,
invokedType, invokedType,
samMethodType, samMethodType,
implMethod, methodHandle,
instantiatedMethodType instantiatedMethodType
); );
//noinspection unchecked //noinspection unchecked

View File

@ -1,6 +1,7 @@
package cn.hutool.core.reflect; package cn.hutool.core.reflect;
import cn.hutool.core.exceptions.UtilException; import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.caller.CallerUtil;
import cn.hutool.core.util.JdkUtil; import cn.hutool.core.util.JdkUtil;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
@ -42,6 +43,16 @@ public class LookupFactory {
} }
} }
/**
* jdk8中如果直接调用{@link MethodHandles#lookup()}获取到的{@link MethodHandles.Lookup}在调用findSpecial和unreflectSpecial
* 时会出现权限不够问题抛出"no private access for invokespecial"异常因此针对JDK8及JDK9+分别封装lookup方法
*
* @return {@link MethodHandles.Lookup}
*/
public static MethodHandles.Lookup lookup() {
return lookup(CallerUtil.getCaller());
}
/** /**
* jdk8中如果直接调用{@link MethodHandles#lookup()}获取到的{@link MethodHandles.Lookup}在调用findSpecial和unreflectSpecial * jdk8中如果直接调用{@link MethodHandles#lookup()}获取到的{@link MethodHandles.Lookup}在调用findSpecial和unreflectSpecial
* 时会出现权限不够问题抛出"no private access for invokespecial"异常因此针对JDK8及JDK9+分别封装lookup方法 * 时会出现权限不够问题抛出"no private access for invokespecial"异常因此针对JDK8及JDK9+分别封装lookup方法

View File

@ -1,12 +1,14 @@
package cn.hutool.core.reflect; package cn.hutool.core.reflect;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.exceptions.UtilException; import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.lang.reflect.Method; import java.lang.reflect.Method;
/** /**
@ -28,6 +30,24 @@ import java.lang.reflect.Method;
*/ */
public class MethodHandleUtil { public class MethodHandleUtil {
/**
* {@link Method}或者{@link Constructor} 包装为方法句柄{@link MethodHandle}
*
* @param methodOrConstructor {@link Method}或者{@link Constructor}
* @return 方法句柄{@link MethodHandle}
*/
public static MethodHandle unreflect(final Member methodOrConstructor) {
try {
if (methodOrConstructor instanceof Method) {
return LookupFactory.lookup().unreflect((Method) methodOrConstructor);
} else {
return LookupFactory.lookup().unreflectConstructor((Constructor<?>) methodOrConstructor);
}
} catch (final IllegalAccessException e) {
throw new UtilException(e);
}
}
/** /**
* 查找指定方法的方法句柄<br> * 查找指定方法的方法句柄<br>
* 此方法只会查找 * 此方法只会查找