This commit is contained in:
Looly 2023-04-06 00:49:58 +08:00
parent 9b87961e03
commit 43bada713d
8 changed files with 264 additions and 123 deletions

View File

@ -16,8 +16,11 @@ import org.dromara.hutool.core.exceptions.UtilException;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.lang.mutable.MutableEntry;
import org.dromara.hutool.core.map.WeakConcurrentMap;
import org.dromara.hutool.core.reflect.*;
import org.dromara.hutool.core.reflect.*;
import org.dromara.hutool.core.reflect.MethodHandleUtil;
import org.dromara.hutool.core.reflect.MethodUtil;
import org.dromara.hutool.core.reflect.ModifierUtil;
import org.dromara.hutool.core.reflect.ReflectUtil;
import org.dromara.hutool.core.reflect.lookup.LookupUtil;
import java.io.Serializable;
import java.lang.invoke.*;
@ -103,7 +106,7 @@ public class LambdaFactory {
final boolean isSerializable = Serializable.class.isAssignableFrom(functionInterfaceType);
final Method invokeMethod = abstractMethods.get(0);
final MethodHandles.Lookup caller = LookupFactory.lookup(executable.getDeclaringClass());
final MethodHandles.Lookup caller = LookupUtil.lookup(executable.getDeclaringClass());
final String invokeName = invokeMethod.getName();
final MethodType invokedType = methodType(functionInterfaceType);
final MethodType samMethodType = methodType(invokeMethod.getReturnType(), invokeMethod.getParameterTypes());

View File

@ -1,115 +0,0 @@
/*
* Copyright (c) 2023 looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.core.reflect;
import org.dromara.hutool.core.exceptions.UtilException;
import org.dromara.hutool.core.lang.caller.CallerUtil;
import org.dromara.hutool.core.util.JdkUtil;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* {@link MethodHandles.Lookup}工厂用于创建{@link MethodHandles.Lookup}对象<br>
* {@link MethodHandles.Lookup}是一个方法句柄查找对象用于在指定类中查找符合给定方法名称方法类型的方法句柄
*
* <p>
* jdk8中如果直接调用{@link MethodHandles#lookup()}获取到的{@link MethodHandles.Lookup}在调用findSpecial和unreflectSpecial
* 时会出现权限不够问题抛出"no private access for invokespecial"异常因此针对JDK8及JDK9+分别封装lookup方法
* </p>
*
* <p>
* 参考
* <p><a href="https://blog.csdn.net/u013202238/article/details/108687086">https://blog.csdn.net/u013202238/article/details/108687086</a></p>
*
* @author looly
* @since 5.7.7
*/
public class LookupFactory {
private static final int ALLOWED_MODES = MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
| MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC;
private static Method privateLookupInMethod;
private static Constructor<MethodHandles.Lookup> jdk8LookupConstructor;
static {
if(JdkUtil.IS_JDK8){
// jdk8 这种方式其实也适用于jdk9及以上的版本,但是上面优先,可以避免 jdk9 反射警告
jdk8LookupConstructor = createJdk8LookupConstructor();
} else {
// jdk9+ 开始提供的java.lang.invoke.MethodHandles.privateLookupIn方法
privateLookupInMethod = createJdk9PrivateLookupInMethod();
}
}
/**
* 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
* 时会出现权限不够问题抛出"no private access for invokespecial"异常因此针对JDK8及JDK9+分别封装lookup方法
*
* @param callerClass 被调用的类或接口
* @return {@link MethodHandles.Lookup}
*/
public static MethodHandles.Lookup lookup(final Class<?> callerClass) {
//使用反射,因为当前jdk可能不是java9或以上版本
if (privateLookupInMethod != null) {
try {
return (MethodHandles.Lookup) privateLookupInMethod.invoke(MethodHandles.class, callerClass, MethodHandles.lookup());
} catch (final IllegalAccessException | InvocationTargetException e) {
throw new UtilException(e);
}
}
//jdk 8
try {
return jdk8LookupConstructor.newInstance(callerClass, ALLOWED_MODES);
} catch (final Exception e) {
throw new IllegalStateException("no 'Lookup(Class, int)' method in java.lang.invoke.MethodHandles.", e);
}
}
@SuppressWarnings("JavaReflectionMemberAccess")
private static Method createJdk9PrivateLookupInMethod(){
try {
return MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class);
} catch (final NoSuchMethodException e) {
//可能是jdk9 以下版本
throw new IllegalStateException(
"There is no 'privateLookupIn(Class, Lookup)' method in java.lang.invoke.MethodHandles.", e);
}
}
private static Constructor<MethodHandles.Lookup> createJdk8LookupConstructor(){
final Constructor<MethodHandles.Lookup> constructor;
try {
constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
} catch (final NoSuchMethodException e) {
//可能是jdk8 以下版本
throw new IllegalStateException(
"There is no 'Lookup(Class, int)' constructor in java.lang.invoke.MethodHandles.", e);
}
constructor.setAccessible(true);
return constructor;
}
}

View File

@ -14,6 +14,7 @@ package org.dromara.hutool.core.reflect;
import org.dromara.hutool.core.exceptions.UtilException;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.reflect.lookup.LookupUtil;
import org.dromara.hutool.core.text.StrUtil;
import java.lang.invoke.MethodHandle;
@ -51,9 +52,9 @@ public class MethodHandleUtil {
public static MethodHandle unreflect(final Member methodOrConstructor) {
try {
if (methodOrConstructor instanceof Method) {
return LookupFactory.lookup().unreflect((Method) methodOrConstructor);
return LookupUtil.lookup().unreflect((Method) methodOrConstructor);
} else {
return LookupFactory.lookup().unreflectConstructor((Constructor<?>) methodOrConstructor);
return LookupUtil.lookup().unreflectConstructor((Constructor<?>) methodOrConstructor);
}
} catch (final IllegalAccessException e) {
throw new UtilException(e);
@ -80,7 +81,7 @@ public class MethodHandleUtil {
}
MethodHandle handle = null;
final MethodHandles.Lookup lookup = LookupFactory.lookup(callerClass);
final MethodHandles.Lookup lookup = LookupUtil.lookup(callerClass);
try {
handle = lookup.findVirtual(callerClass, name, type);
} catch (final IllegalAccessException | NoSuchMethodException ignore) {
@ -129,7 +130,7 @@ public class MethodHandleUtil {
* @return 构造方法句柄
*/
public static MethodHandle findConstructor(final Class<?> callerClass, final MethodType type) {
final MethodHandles.Lookup lookup = LookupFactory.lookup(callerClass);
final MethodHandles.Lookup lookup = LookupUtil.lookup(callerClass);
try {
return lookup.findConstructor(callerClass, type);
} catch (final NoSuchMethodException e) {
@ -252,7 +253,7 @@ public class MethodHandleUtil {
public static <T> T invoke(final boolean isSpecial, final Object obj, final Method method, final Object... args) {
Assert.notNull(method, "Method must be not null!");
final Class<?> declaringClass = method.getDeclaringClass();
final MethodHandles.Lookup lookup = LookupFactory.lookup(declaringClass);
final MethodHandles.Lookup lookup = LookupUtil.lookup(declaringClass);
try {
MethodHandle handle = isSpecial ? lookup.unreflectSpecial(method, declaringClass)
: lookup.unreflect(method);

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2023 looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.core.reflect.lookup;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
/**
* jdk8中如果直接调用{@link MethodHandles#lookup()}获取到的{@link MethodHandles.Lookup}<br>
* 在调用findSpecial和unreflectSpecial时会出现权限不够问题抛出"no private access for invokespecial"异常<br>
* 所以通过反射创建MethodHandles.Lookup解决该问题
* <p>
* 参考https://blog.csdn.net/u013202238/article/details/108687086
*
* @author looly
* @since 6.0.0
*/
public class ConstructorLookupFactory implements LookupFactory {
private static final int ALLOWED_MODES = MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
| MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC;
private final Constructor<MethodHandles.Lookup> lookupConstructor;
/**
* 构造
*/
public ConstructorLookupFactory() {
this.lookupConstructor = createLookupConstructor();
}
@Override
public MethodHandles.Lookup lookup(final Class<?> callerClass) {
try {
return lookupConstructor.newInstance(callerClass, ALLOWED_MODES);
} catch (final Exception e) {
throw new IllegalStateException("no 'Lookup(Class, int)' method in java.lang.invoke.MethodHandles.", e);
}
}
private static Constructor<MethodHandles.Lookup> createLookupConstructor() {
final Constructor<MethodHandles.Lookup> constructor;
try {
constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
} catch (final NoSuchMethodException e) {
//可能是jdk8 以下版本
throw new IllegalStateException(
"There is no 'Lookup(Class, int)' constructor in java.lang.invoke.MethodHandles.", e);
}
constructor.setAccessible(true);
return constructor;
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2023 looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.core.reflect.lookup;
import java.lang.invoke.MethodHandles;
/**
* {@link MethodHandles.Lookup}方法工厂用于创建{@link MethodHandles.Lookup}对象<br>
* {@link MethodHandles.Lookup}是一个方法句柄查找对象用于在指定类中查找符合给定方法名称方法类型的方法句柄
*
* <p>
* 参考https://blog.csdn.net/u013202238/article/details/108687086
* </p>
*
* @author looly
* @since 6.0.0
*/
public interface LookupFactory {
/**
* jdk8中如果直接调用{@link MethodHandles#lookup()}获取到的{@link MethodHandles.Lookup}在调用findSpecial和unreflectSpecial
* 时会出现权限不够问题抛出"no private access for invokespecial"异常因此针对JDK8及JDK9+分别封装lookup方法
*
* @param callerClass 被调用的类或接口
* @return {@link MethodHandles.Lookup}
*/
MethodHandles.Lookup lookup(final Class<?> callerClass);
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2023 looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.core.reflect.lookup;
import org.dromara.hutool.core.lang.caller.CallerUtil;
import org.dromara.hutool.core.util.JdkUtil;
import java.lang.invoke.MethodHandles;
/**
* {@link MethodHandles.Lookup}工厂工具用于创建{@link MethodHandles.Lookup}对象<br>
* {@link MethodHandles.Lookup}是一个方法句柄查找对象用于在指定类中查找符合给定方法名称方法类型的方法句柄
*
* <p>
* jdk8中如果直接调用{@link MethodHandles#lookup()}获取到的{@link MethodHandles.Lookup}在调用findSpecial和unreflectSpecial
* 时会出现权限不够问题抛出"no private access for invokespecial"异常因此针对JDK8及JDK9+分别封装lookup方法
* </p>
*
* <p>
* 参考https://blog.csdn.net/u013202238/article/details/108687086
*
* @author looly
* @since 6.0.0
*/
public class LookupUtil {
private static final LookupFactory factory;
static {
if (JdkUtil.IS_JDK8) {
factory = new ConstructorLookupFactory();
} else {
factory = new MethodLookupFactory();
}
}
/**
* 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
* 时会出现权限不够问题抛出"no private access for invokespecial"异常因此针对JDK8及JDK9+分别封装lookup方法
*
* @param callerClass 被调用的类或接口
* @return {@link MethodHandles.Lookup}
*/
public static MethodHandles.Lookup lookup(final Class<?> callerClass) {
return factory.lookup(callerClass);
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2023 looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.core.reflect.lookup;
import org.dromara.hutool.core.exceptions.UtilException;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* jdk11中直接调用MethodHandles.lookup()获取到的MethodHandles.Lookup只能对接口类型才会权限获取方法的方法句柄MethodHandle
* 如果是普通类型Class,需要使用jdk9开始提供的 MethodHandles#privateLookupIn(java.lang.Class, java.lang.invoke.MethodHandles.Lookup)方法.
* <p>
* 参考https://blog.csdn.net/u013202238/article/details/108687086
*
* @author looly
* @since 6.0.0
*/
public class MethodLookupFactory implements LookupFactory {
private final Method privateLookupInMethod;
/**
* 构造
*/
public MethodLookupFactory() {
this.privateLookupInMethod = createJdk9PrivateLookupInMethod();
}
@Override
public MethodHandles.Lookup lookup(final Class<?> callerClass) {
try {
return (MethodHandles.Lookup) privateLookupInMethod.invoke(MethodHandles.class, callerClass, MethodHandles.lookup());
} catch (final IllegalAccessException | InvocationTargetException e) {
throw new UtilException(e);
}
}
@SuppressWarnings("JavaReflectionMemberAccess")
private static Method createJdk9PrivateLookupInMethod() {
try {
return MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class);
} catch (final NoSuchMethodException e) {
//可能是jdk9 以下版本
throw new IllegalStateException(
"There is no 'privateLookupIn(Class, Lookup)' method in java.lang.invoke.MethodHandles.", e);
}
}
}

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2023 looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* {@link java.lang.invoke.MethodHandles.Lookup} 创建封装<br>
* <p>
* jdk8中如果直接调用{@link java.lang.invoke.MethodHandles#lookup()}获取到的{@link java.lang.invoke.MethodHandles.Lookup}在调用findSpecial和unreflectSpecial
* 时会出现权限不够问题抛出"no private access for invokespecial"异常因此针对JDK8及JDK9+分别封装lookup方法
* </p>
*
* <p>
* 参考
* <p><a href="https://blog.csdn.net/u013202238/article/details/108687086">https://blog.csdn.net/u013202238/article/details/108687086</a></p>
*/
package org.dromara.hutool.core.reflect.lookup;