diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/reflect/MethodHandleUtil.java b/hutool-core/src/main/java/cn/hutool/core/lang/reflect/MethodHandleUtil.java
index 9511a2867..1fd44d0df 100755
--- a/hutool-core/src/main/java/cn/hutool/core/lang/reflect/MethodHandleUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/lang/reflect/MethodHandleUtil.java
@@ -1,9 +1,12 @@
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 java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
/**
@@ -29,6 +32,53 @@ public class MethodHandleUtil {
return LookupFactory.lookup(callerClass);
}
+ /**
+ * 查找指定方法的方法句柄
+ * 此方法只会查找:
+ *
+ * - 当前类的方法(包括构造方法和private方法)
+ * - 父类的方法(包括构造方法和private方法)
+ * - 当前类的static方法
+ *
+ *
+ * @param callerClass 方法所在类或接口
+ * @param name 方法名称
+ * @param type 返回类型和参数类型
+ * @return 方法句柄 {@link MethodHandle},{@code null}表示未找到方法
+ */
+ public static MethodHandle findMethod(Class> callerClass, String name, MethodType 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;
+ }
+
/**
* 执行Interface中的default方法
*
@@ -45,18 +95,50 @@ public class MethodHandleUtil {
* MethodHandleUtil::invokeDefault);
*
*
- * @param o 接口的子对象或代理对象
+ * @param obj 接口的子对象或代理对象
+ * @param methodName 方法名称
+ * @param args 参数
+ * @return 结果
+ */
+ public static T invoke(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 invoke(obj, method, args);
+ }
+
+ /**
+ * 执行Interface中的default方法
+ *
+ *
+ * interface Duck {
+ * default String quack() {
+ * return "Quack";
+ * }
+ * }
+ *
+ * Duck duck = (Duck) Proxy.newProxyInstance(
+ * ClassLoaderUtil.getClassLoader(),
+ * new Class[] { Duck.class },
+ * MethodHandleUtil::invokeDefault);
+ *
+ *
+ * @param obj 接口的子对象或代理对象
* @param method 方法
* @param args 参数
* @return 结果
*/
@SuppressWarnings("unchecked")
- public static T invoke(Object o, Method method, Object... args) {
+ public static T invoke(Object obj, Method method, Object... args) {
final Class> declaringClass = method.getDeclaringClass();
try {
return (T) lookup(declaringClass)
.unreflectSpecial(method, declaringClass)
- .bindTo(o)
+ .bindTo(obj)
.invokeWithArguments(args);
} catch (Throwable e) {
throw new UtilException(e);
diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java
index 28b26a661..a96fda282 100644
--- a/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java
@@ -944,9 +944,12 @@ public class ReflectUtil {
* @since 3.1.2
*/
public static T invoke(Object obj, String methodName, Object... args) throws UtilException {
+ Assert.notNull(obj, "Object to get method must be not null!");
+ Assert.notBlank(methodName, "Method name must be not blank!");
+
final Method method = getMethodOfObj(obj, methodName, args);
if (null == method) {
- throw new UtilException(StrUtil.format("No such method: [{}]", methodName));
+ throw new UtilException("No such method: [{}] from [{}]", methodName, obj.getClass());
}
return invoke(obj, method, args);
}
diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/reflect/MethodHandleUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/reflect/MethodHandleUtilTest.java
index a955dcd67..2772fee10 100755
--- a/hutool-core/src/test/java/cn/hutool/core/lang/reflect/MethodHandleUtilTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/lang/reflect/MethodHandleUtilTest.java
@@ -5,6 +5,8 @@ import cn.hutool.core.util.ReflectUtil;
import org.junit.Assert;
import org.junit.Test;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
@@ -39,6 +41,16 @@ public class MethodHandleUtilTest {
Assert.assertEquals("Quack", duck.quack());
}
+ @Test
+ public void invokeStaticTest(){
+ Duck duck = (Duck) Proxy.newProxyInstance(
+ ClassLoaderUtil.getClassLoader(),
+ new Class[] { Duck.class },
+ ReflectUtil::invoke);
+
+ Assert.assertEquals("Quack", duck.quack());
+ }
+
@Test
public void invokeTest(){
// 测试执行普通方法
@@ -47,15 +59,88 @@ public class MethodHandleUtilTest {
Assert.assertEquals(36, size);
}
+ @Test
+ public void findMethodTest() throws Throwable {
+ MethodHandle handle = MethodHandleUtil.findMethod(Duck.class, "quack",
+ MethodType.methodType(String.class));
+ Assert.assertNotNull(handle);
+ // 对象方法自行需要绑定对象或者传入对象参数
+ String invoke = (String) handle.invoke(new BigDuck());
+ Assert.assertEquals("Quack", invoke);
+
+ // 对象的方法获取
+ handle = MethodHandleUtil.findMethod(BigDuck.class, "getSize",
+ MethodType.methodType(int.class));
+ Assert.assertNotNull(handle);
+ int invokeInt = (int) handle.invoke(new BigDuck());
+ Assert.assertEquals(36, invokeInt);
+ }
+
+ @Test
+ public void findStaticMethodTest() throws Throwable {
+ final MethodHandle handle = MethodHandleUtil.findMethod(Duck.class, "getDuck",
+ MethodType.methodType(String.class, int.class));
+ Assert.assertNotNull(handle);
+
+ // static 方法执行不需要绑定或者传入对象,直接传入参数即可
+ final String invoke = (String) handle.invoke(12);
+ Assert.assertEquals("Duck 12", invoke);
+ }
+
+ @Test
+ public void findPrivateMethodTest() throws Throwable {
+ final MethodHandle handle = MethodHandleUtil.findMethod(BigDuck.class, "getPrivateValue",
+ MethodType.methodType(String.class));
+ Assert.assertNotNull(handle);
+
+ final String invoke = (String) handle.invoke(new BigDuck());
+ Assert.assertEquals("private value", invoke);
+ }
+
+ @Test
+ public void findSuperMethodTest() throws Throwable {
+ // 查找父类的方法
+ final MethodHandle handle = MethodHandleUtil.findMethod(BigDuck.class, "quack",
+ MethodType.methodType(String.class));
+ Assert.assertNotNull(handle);
+
+ final String invoke = (String) handle.invoke(new BigDuck());
+ Assert.assertEquals("Quack", invoke);
+ }
+
+ @Test
+ public void findPrivateStaticMethodTest() throws Throwable {
+ final MethodHandle handle = MethodHandleUtil.findMethod(BigDuck.class, "getPrivateStaticValue",
+ MethodType.methodType(String.class));
+ Assert.assertNotNull(handle);
+
+ final String invoke = (String) handle.invoke();
+ Assert.assertEquals("private static value", invoke);
+ }
+
interface Duck {
default String quack() {
return "Quack";
}
+
+ static String getDuck(int count){
+ return "Duck " + count;
+ }
}
static class BigDuck implements Duck{
public int getSize(){
return 36;
}
+
+ @SuppressWarnings("unused")
+ private String getPrivateValue(){
+ return "private value";
+ }
+
+ @SuppressWarnings("unused")
+ private static String getPrivateStaticValue(){
+ return "private static value";
+ }
}
}