cn.hutool.core.lang.reflect.MethodHandleUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hutool-all Show documentation
Show all versions of hutool-all Show documentation
Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。
package cn.hutool.core.lang.reflect;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
/**
* 方法句柄{@link MethodHandle}封装工具类
* 方法句柄是一个有类型的,可以直接执行的指向底层方法、构造器、field等的引用,可以简单理解为函数指针,它是一种更加底层的查找、调整和调用方法的机制。
* 参考:
*
* - https://stackoverflow.com/questions/22614746/how-do-i-invoke-java-8-default-methods-reflectively
*
*
* @author looly
* @since 5.7.7
*/
public class MethodHandleUtil {
/**
* 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(Class> callerClass) {
return LookupFactory.lookup(callerClass);
}
/**
* 查找指定方法的方法句柄
* 此方法只会查找:
*
* - 当前类的方法(包括构造方法和private方法)
* - 父类的方法(包括构造方法和private方法)
* - 当前类的static方法
*
*
* @param callerClass 方法所在类或接口
* @param name 方法名称,{@code null}或者空则查找构造方法
* @param type 返回类型和参数类型
* @return 方法句柄 {@link MethodHandle},{@code null}表示未找到方法
*/
public static MethodHandle findMethod(Class> callerClass, String name, MethodType type) {
if (StrUtil.isBlank(name)) {
return findConstructor(callerClass, type);
}
MethodHandle handle = null;
final MethodHandles.Lookup lookup = lookup(callerClass);
try {
handle = lookup.findVirtual(callerClass, name, type);
} catch (IllegalAccessException | NoSuchMethodException ignore) {
//ignore
}
// static方法
if (null == handle) {
try {
handle = lookup.findStatic(callerClass, name, type);
} catch (IllegalAccessException | NoSuchMethodException ignore) {
//ignore
}
}
// 特殊方法,包括构造方法、私有方法等
if (null == handle) {
try {
handle = lookup.findSpecial(callerClass, name, type, callerClass);
} catch (NoSuchMethodException ignore) {
//ignore
} catch (IllegalAccessException e) {
throw new UtilException(e);
}
}
return handle;
}
/**
* 查找指定的构造方法
*
* @param callerClass 类
* @param args 参数
* @return 构造方法句柄
*/
public static MethodHandle findConstructor(Class> callerClass, Class>... args) {
return findConstructor(callerClass, MethodType.methodType(void.class, args));
}
/**
* 查找指定的构造方法
*
* @param callerClass 类
* @param type 参数类型,此处返回类型应为void.class
* @return 构造方法句柄
*/
public static MethodHandle findConstructor(Class> callerClass, MethodType type) {
final MethodHandles.Lookup lookup = lookup(callerClass);
try {
return lookup.findConstructor(callerClass, type);
} catch (NoSuchMethodException e) {
return null;
} catch (IllegalAccessException e) {
throw new UtilException(e);
}
}
/**
* 执行接口或对象中的特殊方法(private、static等)
*
*
* interface Duck {
* default String quack() {
* return "Quack";
* }
* }
*
* Duck duck = (Duck) Proxy.newProxyInstance(
* ClassLoaderUtil.getClassLoader(),
* new Class[] { Duck.class },
* MethodHandleUtil::invokeDefault);
*
*
* @param 返回结果类型
* @param obj 接口的子对象或代理对象
* @param methodName 方法名称
* @param args 参数
* @return 结果
*/
public static T invokeSpecial(Object obj, String methodName, Object... args) {
Assert.notNull(obj, "Object to get method must be not null!");
Assert.notBlank(methodName, "Method name must be not blank!");
final Method method = ReflectUtil.getMethodOfObj(obj, methodName, args);
if (null == method) {
throw new UtilException("No such method: [{}] from [{}]", methodName, obj.getClass());
}
return invokeSpecial(obj, method, args);
}
/**
* 执行接口或对象中的方法
*
* @param 返回结果类型
* @param obj 接口的子对象或代理对象
* @param method 方法
* @param args 参数
* @return 结果
*/
public static T invoke(Object obj, Method method, Object... args) {
return invoke(false, obj, method, args);
}
/**
* 执行接口或对象中的特殊方法(private、static等)
*
*
* interface Duck {
* default String quack() {
* return "Quack";
* }
* }
*
* Duck duck = (Duck) Proxy.newProxyInstance(
* ClassLoaderUtil.getClassLoader(),
* new Class[] { Duck.class },
* MethodHandleUtil::invoke);
*
*
* @param 返回结果类型
* @param obj 接口的子对象或代理对象
* @param method 方法
* @param args 参数
* @return 结果
*/
public static T invokeSpecial(Object obj, Method method, Object... args) {
return invoke(true, obj, method, args);
}
/**
* 执行接口或对象中的方法
*
*
* interface Duck {
* default String quack() {
* return "Quack";
* }
* }
*
* Duck duck = (Duck) Proxy.newProxyInstance(
* ClassLoaderUtil.getClassLoader(),
* new Class[] { Duck.class },
* MethodHandleUtil::invoke);
*
*
* @param 返回结果类型
* @param isSpecial 是否为特殊方法(private、static等)
* @param obj 接口的子对象或代理对象
* @param method 方法
* @param args 参数
* @return 结果
*/
@SuppressWarnings("unchecked")
public static T invoke(boolean isSpecial, Object obj, Method method, Object... args) {
Assert.notNull(method, "Method must be not null!");
final Class> declaringClass = method.getDeclaringClass();
final MethodHandles.Lookup lookup = lookup(declaringClass);
try {
MethodHandle handle = isSpecial ? lookup.unreflectSpecial(method, declaringClass)
: lookup.unreflect(method);
if (null != obj) {
handle = handle.bindTo(obj);
}
return (T) handle.invokeWithArguments(args);
} catch (Throwable e) {
throw new UtilException(e);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy