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); } + /** + * 查找指定方法的方法句柄
+ * 此方法只会查找: + * + * + * @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"; + } } }