From 50c9337ea05c9bba2a2881488dd7fced48232ff8 Mon Sep 17 00:00:00 2001 From: Looly Date: Wed, 28 Jul 2021 23:18:31 +0800 Subject: [PATCH] add methods --- .../core/lang/reflect/MethodHandleUtil.java | 106 +++++++++++++++--- .../java/cn/hutool/core/util/ReflectUtil.java | 2 +- .../lang/reflect/MethodHandleUtilTest.java | 16 ++- 3 files changed, 103 insertions(+), 21 deletions(-) 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 1fd44d0df..50d80525f 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 @@ -3,6 +3,7 @@ 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; @@ -42,13 +43,16 @@ public class MethodHandleUtil { * * * @param callerClass 方法所在类或接口 - * @param name 方法名称 - * @param type 返回类型和参数类型 + * @param name 方法名称,{@link null}或者空则查找构造方法 + * @param type 返回类型和参数类型 * @return 方法句柄 {@link MethodHandle},{@code null}表示未找到方法 */ - public static MethodHandle findMethod(Class callerClass, String name, MethodType type){ - MethodHandle handle = 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); @@ -57,7 +61,7 @@ public class MethodHandleUtil { } // static方法 - if(null == handle){ + if (null == handle) { try { handle = lookup.findStatic(callerClass, name, type); } catch (IllegalAccessException | NoSuchMethodException ignore) { @@ -66,7 +70,7 @@ public class MethodHandleUtil { } // 特殊方法,包括构造方法、私有方法等 - if(null == handle){ + if (null == handle) { try { handle = lookup.findSpecial(callerClass, name, type, callerClass); } catch (NoSuchMethodException ignore) { @@ -80,7 +84,36 @@ public class MethodHandleUtil { } /** - * 执行Interface中的default方法
+ * 查找指定的构造方法 + * + * @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); + } + } + + /** + * 执行接口或对象中的方法
* *
 	 *     interface Duck {
@@ -100,7 +133,7 @@ public class MethodHandleUtil {
 	 * @param args       参数
 	 * @return 结果
 	 */
-	public static  T invoke(Object obj, String methodName, Object... args) {
+	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!");
 
@@ -108,11 +141,23 @@ public class MethodHandleUtil {
 		if (null == method) {
 			throw new UtilException("No such method: [{}] from [{}]", methodName, obj.getClass());
 		}
-		return invoke(obj, method, args);
+		return invokeSpecial(obj, method, args);
 	}
 
 	/**
-	 * 执行Interface中的default方法
+ * 执行接口或对象中的方法 + * + * @param obj 接口的子对象或代理对象 + * @param method 方法 + * @param args 参数 + * @return 结果 + */ + public static T invoke(Object obj, Method method, Object... args) { + return invoke(false, obj, method, args); + } + + /** + * 执行接口或对象中的方法
* *
 	 *     interface Duck {
@@ -124,7 +169,32 @@ public class MethodHandleUtil {
 	 *     Duck duck = (Duck) Proxy.newProxyInstance(
 	 *         ClassLoaderUtil.getClassLoader(),
 	 *         new Class[] { Duck.class },
-	 *         MethodHandleUtil::invokeDefault);
+	 *         MethodHandleUtil::invoke);
+	 * 
+ * + * @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 obj 接口的子对象或代理对象 @@ -133,13 +203,17 @@ public class MethodHandleUtil { * @return 结果 */ @SuppressWarnings("unchecked") - public static T invoke(Object obj, Method method, Object... args) { + 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 { - return (T) lookup(declaringClass) - .unreflectSpecial(method, declaringClass) - .bindTo(obj) - .invokeWithArguments(args); + 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); } 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 a96fda282..39afaaaac 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 @@ -920,7 +920,7 @@ public class ReflectUtil { if(method.isDefault()){ // 当方法是default方法时,尤其对象是代理对象,需使用句柄方式执行 // 代理对象情况下调用method.invoke会导致循环引用执行,最终栈溢出 - return MethodHandleUtil.invoke(obj, method, args); + return MethodHandleUtil.invokeSpecial(obj, method, args); } try { 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 2772fee10..3eb2120ae 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 @@ -17,13 +17,13 @@ public class MethodHandleUtilTest { Duck duck = (Duck) Proxy.newProxyInstance( ClassLoaderUtil.getClassLoader(), new Class[] { Duck.class }, - MethodHandleUtil::invoke); + MethodHandleUtil::invokeSpecial); Assert.assertEquals("Quack", duck.quack()); // 测试子类执行default方法 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); // 测试反射执行默认方法 @@ -42,7 +42,7 @@ public class MethodHandleUtilTest { } @Test - public void invokeStaticTest(){ + public void invokeStaticByProxyTest(){ Duck duck = (Duck) Proxy.newProxyInstance( ClassLoaderUtil.getClassLoader(), new Class[] { Duck.class }, @@ -54,11 +54,19 @@ public class MethodHandleUtilTest { @Test public void invokeTest(){ // 测试执行普通方法 - final int size = MethodHandleUtil.invoke(new BigDuck(), + final int size = MethodHandleUtil.invokeSpecial(new BigDuck(), ReflectUtil.getMethod(BigDuck.class, "getSize")); 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 public void findMethodTest() throws Throwable { MethodHandle handle = MethodHandleUtil.findMethod(Duck.class, "quack",