mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
add methods
This commit is contained in:
parent
520b503065
commit
50c9337ea0
@ -3,6 +3,7 @@ package cn.hutool.core.lang.reflect;
|
|||||||
import cn.hutool.core.exceptions.UtilException;
|
import cn.hutool.core.exceptions.UtilException;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.ReflectUtil;
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
@ -42,13 +43,16 @@ public class MethodHandleUtil {
|
|||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param callerClass 方法所在类或接口
|
* @param callerClass 方法所在类或接口
|
||||||
* @param name 方法名称
|
* @param name 方法名称,{@link null}或者空则查找构造方法
|
||||||
* @param type 返回类型和参数类型
|
* @param type 返回类型和参数类型
|
||||||
* @return 方法句柄 {@link MethodHandle},{@code null}表示未找到方法
|
* @return 方法句柄 {@link MethodHandle},{@code null}表示未找到方法
|
||||||
*/
|
*/
|
||||||
public static MethodHandle findMethod(Class<?> callerClass, String name, MethodType type){
|
public static MethodHandle findMethod(Class<?> callerClass, String name, MethodType type) {
|
||||||
MethodHandle handle = null;
|
if (StrUtil.isBlank(name)) {
|
||||||
|
return findConstructor(callerClass, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodHandle handle = null;
|
||||||
final MethodHandles.Lookup lookup = lookup(callerClass);
|
final MethodHandles.Lookup lookup = lookup(callerClass);
|
||||||
try {
|
try {
|
||||||
handle = lookup.findVirtual(callerClass, name, type);
|
handle = lookup.findVirtual(callerClass, name, type);
|
||||||
@ -57,7 +61,7 @@ public class MethodHandleUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// static方法
|
// static方法
|
||||||
if(null == handle){
|
if (null == handle) {
|
||||||
try {
|
try {
|
||||||
handle = lookup.findStatic(callerClass, name, type);
|
handle = lookup.findStatic(callerClass, name, type);
|
||||||
} catch (IllegalAccessException | NoSuchMethodException ignore) {
|
} catch (IllegalAccessException | NoSuchMethodException ignore) {
|
||||||
@ -66,7 +70,7 @@ public class MethodHandleUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 特殊方法,包括构造方法、私有方法等
|
// 特殊方法,包括构造方法、私有方法等
|
||||||
if(null == handle){
|
if (null == handle) {
|
||||||
try {
|
try {
|
||||||
handle = lookup.findSpecial(callerClass, name, type, callerClass);
|
handle = lookup.findSpecial(callerClass, name, type, callerClass);
|
||||||
} catch (NoSuchMethodException ignore) {
|
} catch (NoSuchMethodException ignore) {
|
||||||
@ -80,7 +84,36 @@ public class MethodHandleUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行Interface中的default方法<br>
|
* 查找指定的构造方法
|
||||||
|
*
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行接口或对象中的方法<br>
|
||||||
*
|
*
|
||||||
* <pre class="code">
|
* <pre class="code">
|
||||||
* interface Duck {
|
* interface Duck {
|
||||||
@ -100,7 +133,7 @@ public class MethodHandleUtil {
|
|||||||
* @param args 参数
|
* @param args 参数
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
public static <T> T invoke(Object obj, String methodName, Object... args) {
|
public static <T> T invokeSpecial(Object obj, String methodName, Object... args) {
|
||||||
Assert.notNull(obj, "Object to get method must be not null!");
|
Assert.notNull(obj, "Object to get method must be not null!");
|
||||||
Assert.notBlank(methodName, "Method name must be not blank!");
|
Assert.notBlank(methodName, "Method name must be not blank!");
|
||||||
|
|
||||||
@ -108,11 +141,23 @@ public class MethodHandleUtil {
|
|||||||
if (null == method) {
|
if (null == method) {
|
||||||
throw new UtilException("No such method: [{}] from [{}]", methodName, obj.getClass());
|
throw new UtilException("No such method: [{}] from [{}]", methodName, obj.getClass());
|
||||||
}
|
}
|
||||||
return invoke(obj, method, args);
|
return invokeSpecial(obj, method, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行Interface中的default方法<br>
|
* 执行接口或对象中的方法
|
||||||
|
*
|
||||||
|
* @param obj 接口的子对象或代理对象
|
||||||
|
* @param method 方法
|
||||||
|
* @param args 参数
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public static <T> T invoke(Object obj, Method method, Object... args) {
|
||||||
|
return invoke(false, obj, method, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行接口或对象中的方法<br>
|
||||||
*
|
*
|
||||||
* <pre class="code">
|
* <pre class="code">
|
||||||
* interface Duck {
|
* interface Duck {
|
||||||
@ -124,7 +169,32 @@ public class MethodHandleUtil {
|
|||||||
* Duck duck = (Duck) Proxy.newProxyInstance(
|
* Duck duck = (Duck) Proxy.newProxyInstance(
|
||||||
* ClassLoaderUtil.getClassLoader(),
|
* ClassLoaderUtil.getClassLoader(),
|
||||||
* new Class[] { Duck.class },
|
* new Class[] { Duck.class },
|
||||||
* MethodHandleUtil::invokeDefault);
|
* MethodHandleUtil::invoke);
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param obj 接口的子对象或代理对象
|
||||||
|
* @param method 方法
|
||||||
|
* @param args 参数
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public static <T> T invokeSpecial(Object obj, Method method, Object... args) {
|
||||||
|
return invoke(true, obj, method, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行接口或对象中的方法<br>
|
||||||
|
*
|
||||||
|
* <pre class="code">
|
||||||
|
* interface Duck {
|
||||||
|
* default String quack() {
|
||||||
|
* return "Quack";
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Duck duck = (Duck) Proxy.newProxyInstance(
|
||||||
|
* ClassLoaderUtil.getClassLoader(),
|
||||||
|
* new Class[] { Duck.class },
|
||||||
|
* MethodHandleUtil::invoke);
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @param obj 接口的子对象或代理对象
|
* @param obj 接口的子对象或代理对象
|
||||||
@ -133,13 +203,17 @@ public class MethodHandleUtil {
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T> T invoke(Object obj, Method method, Object... args) {
|
public static <T> T invoke(boolean isSpecial, Object obj, Method method, Object... args) {
|
||||||
|
Assert.notNull(method, "Method must be not null!");
|
||||||
final Class<?> declaringClass = method.getDeclaringClass();
|
final Class<?> declaringClass = method.getDeclaringClass();
|
||||||
|
final MethodHandles.Lookup lookup = lookup(declaringClass);
|
||||||
try {
|
try {
|
||||||
return (T) lookup(declaringClass)
|
MethodHandle handle = isSpecial ? lookup.unreflectSpecial(method, declaringClass)
|
||||||
.unreflectSpecial(method, declaringClass)
|
: lookup.unreflect(method);
|
||||||
.bindTo(obj)
|
if(null != obj){
|
||||||
.invokeWithArguments(args);
|
handle = handle.bindTo(obj);
|
||||||
|
}
|
||||||
|
return (T) handle.invokeWithArguments(args);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
throw new UtilException(e);
|
throw new UtilException(e);
|
||||||
}
|
}
|
||||||
|
@ -920,7 +920,7 @@ public class ReflectUtil {
|
|||||||
if(method.isDefault()){
|
if(method.isDefault()){
|
||||||
// 当方法是default方法时,尤其对象是代理对象,需使用句柄方式执行
|
// 当方法是default方法时,尤其对象是代理对象,需使用句柄方式执行
|
||||||
// 代理对象情况下调用method.invoke会导致循环引用执行,最终栈溢出
|
// 代理对象情况下调用method.invoke会导致循环引用执行,最终栈溢出
|
||||||
return MethodHandleUtil.invoke(obj, method, args);
|
return MethodHandleUtil.invokeSpecial(obj, method, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -17,13 +17,13 @@ public class MethodHandleUtilTest {
|
|||||||
Duck duck = (Duck) Proxy.newProxyInstance(
|
Duck duck = (Duck) Proxy.newProxyInstance(
|
||||||
ClassLoaderUtil.getClassLoader(),
|
ClassLoaderUtil.getClassLoader(),
|
||||||
new Class[] { Duck.class },
|
new Class[] { Duck.class },
|
||||||
MethodHandleUtil::invoke);
|
MethodHandleUtil::invokeSpecial);
|
||||||
|
|
||||||
Assert.assertEquals("Quack", duck.quack());
|
Assert.assertEquals("Quack", duck.quack());
|
||||||
|
|
||||||
// 测试子类执行default方法
|
// 测试子类执行default方法
|
||||||
final Method quackMethod = ReflectUtil.getMethod(Duck.class, "quack");
|
final Method quackMethod = ReflectUtil.getMethod(Duck.class, "quack");
|
||||||
String quack = MethodHandleUtil.invoke(new BigDuck(), quackMethod);
|
String quack = MethodHandleUtil.invokeSpecial(new BigDuck(), quackMethod);
|
||||||
Assert.assertEquals("Quack", quack);
|
Assert.assertEquals("Quack", quack);
|
||||||
|
|
||||||
// 测试反射执行默认方法
|
// 测试反射执行默认方法
|
||||||
@ -42,7 +42,7 @@ public class MethodHandleUtilTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void invokeStaticTest(){
|
public void invokeStaticByProxyTest(){
|
||||||
Duck duck = (Duck) Proxy.newProxyInstance(
|
Duck duck = (Duck) Proxy.newProxyInstance(
|
||||||
ClassLoaderUtil.getClassLoader(),
|
ClassLoaderUtil.getClassLoader(),
|
||||||
new Class[] { Duck.class },
|
new Class[] { Duck.class },
|
||||||
@ -54,11 +54,19 @@ public class MethodHandleUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void invokeTest(){
|
public void invokeTest(){
|
||||||
// 测试执行普通方法
|
// 测试执行普通方法
|
||||||
final int size = MethodHandleUtil.invoke(new BigDuck(),
|
final int size = MethodHandleUtil.invokeSpecial(new BigDuck(),
|
||||||
ReflectUtil.getMethod(BigDuck.class, "getSize"));
|
ReflectUtil.getMethod(BigDuck.class, "getSize"));
|
||||||
Assert.assertEquals(36, size);
|
Assert.assertEquals(36, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void invokeStaticTest(){
|
||||||
|
// 测试执行普通方法
|
||||||
|
final String result = MethodHandleUtil.invoke(null,
|
||||||
|
ReflectUtil.getMethod(Duck.class, "getDuck", int.class), 78);
|
||||||
|
Assert.assertEquals("Duck 78", result);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void findMethodTest() throws Throwable {
|
public void findMethodTest() throws Throwable {
|
||||||
MethodHandle handle = MethodHandleUtil.findMethod(Duck.class, "quack",
|
MethodHandle handle = MethodHandleUtil.findMethod(Duck.class, "quack",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user