ソースを参照

Merge pull request #1205 from Lillls/v5-dev

[新特性]反射调用支持传递参数的值为null
Golden Looly 5 年 前
コミット
e295779330

+ 20 - 0
hutool-core/src/main/java/cn/hutool/core/bean/NullWrapperBean.java

@@ -0,0 +1,20 @@
+package cn.hutool.core.bean;
+
+/**
+ * 为了解决反射过程中,需要传递null参数,但是会丢失参数类型而设立的包装类
+ */
+public class NullWrapperBean {
+
+    private final Class<?> mClasses;
+
+    /**
+     * @param classes null的类型
+     */
+    public NullWrapperBean(Class<?> classes) {
+        this.mClasses = classes;
+    }
+
+    public Class<?> getClasses() {
+        return mClasses;
+    }
+}

+ 16 - 9
hutool-core/src/main/java/cn/hutool/core/util/ClassUtil.java

@@ -1,5 +1,6 @@
 package cn.hutool.core.util;
 
+import cn.hutool.core.bean.NullWrapperBean;
 import cn.hutool.core.convert.BasicType;
 import cn.hutool.core.exceptions.UtilException;
 import cn.hutool.core.io.FileUtil;
@@ -139,15 +140,21 @@ public class ClassUtil {
 	 * @param objects 对象数组,如果数组中存在{@code null}元素,则此元素被认为是Object类型
 	 * @return 类数组
 	 */
-	public static Class<?>[] getClasses(Object... objects) {
-		Class<?>[] classes = new Class<?>[objects.length];
-		Object obj;
-		for (int i = 0; i < objects.length; i++) {
-			obj = objects[i];
-			classes[i] = (null == obj) ? Object.class : obj.getClass();
-		}
-		return classes;
-	}
+    public static Class<?>[] getClasses(Object... objects) {
+        Class<?>[] classes = new Class<?>[objects.length];
+        Object obj;
+        for (int i = 0; i < objects.length; i++) {
+            obj = objects[i];
+            if (obj instanceof NullWrapperBean) {
+                classes[i] = ((NullWrapperBean) obj).getClasses();
+            } else if (null == obj) {
+                classes[i] = Object.class;
+            } else {
+                classes[i] = obj.getClass();
+            }
+        }
+        return classes;
+    }
 
 	/**
 	 * 指定类是否与给定的类名相同

+ 79 - 72
hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java

@@ -1,6 +1,7 @@
 package cn.hutool.core.util;
 
 import cn.hutool.core.annotation.Alias;
+import cn.hutool.core.bean.NullWrapperBean;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.convert.Convert;
 import cn.hutool.core.exceptions.UtilException;
@@ -864,78 +865,84 @@ public class ReflectUtil {
 		return invoke(obj, method, args);
 	}
 
-	/**
-	 * 执行方法
-	 *
-	 * <p>
-	 * 对于用户传入参数会做必要检查,包括:
-	 *
-	 * <pre>
-	 *     1、忽略多余的参数
-	 *     2、参数不够补齐默认值
-	 *     3、传入参数为null,但是目标参数类型为原始类型,做转换
-	 * </pre>
-	 *
-	 * @param <T>    返回对象类型
-	 * @param obj    对象,如果执行静态方法,此值为<code>null</code>
-	 * @param method 方法(对象方法或static方法都可)
-	 * @param args   参数对象
-	 * @return 结果
-	 * @throws UtilException 一些列异常的包装
-	 */
-	@SuppressWarnings("unchecked")
-	public static <T> T invoke(Object obj, Method method, Object... args) throws UtilException {
-		setAccessible(method);
-
-		// 检查用户传入参数:
-		// 1、忽略多余的参数
-		// 2、参数不够补齐默认值
-		// 3、传入参数为null,但是目标参数类型为原始类型,做转换
-		// 4、传入参数类型不对应,尝试转换类型
-		final Class<?>[] parameterTypes = method.getParameterTypes();
-		final Object[] actualArgs = new Object[parameterTypes.length];
-		if (null != args) {
-			for (int i = 0; i < actualArgs.length; i++) {
-				if (i >= args.length || null == args[i]) {
-					// 越界或者空值
-					actualArgs[i] = ClassUtil.getDefaultValue(parameterTypes[i]);
-				} else if (false == parameterTypes[i].isAssignableFrom(args[i].getClass())) {
-					//对于类型不同的字段,尝试转换,转换失败则使用原对象类型
-					final Object targetValue = Convert.convert(parameterTypes[i], args[i]);
-					if (null != targetValue) {
-						actualArgs[i] = targetValue;
-					}
-				} else {
-					actualArgs[i] = args[i];
-				}
-			}
-		}
-
-		try {
-			return (T) method.invoke(ClassUtil.isStatic(method) ? null : obj, actualArgs);
-		} catch (Exception e) {
-			throw new UtilException(e);
-		}
-	}
-
-	/**
-	 * 执行对象中指定方法
-	 *
-	 * @param <T>        返回对象类型
-	 * @param obj        方法所在对象
-	 * @param methodName 方法名
-	 * @param args       参数列表
-	 * @return 执行结果
-	 * @throws UtilException IllegalAccessException包装
-	 * @since 3.1.2
-	 */
-	public static <T> T invoke(Object obj, String methodName, Object... args) throws UtilException {
-		final Method method = getMethodOfObj(obj, methodName, args);
-		if (null == method) {
-			throw new UtilException(StrUtil.format("No such method: [{}]", methodName));
-		}
-		return invoke(obj, method, args);
-	}
+    /**
+     * 执行方法
+     *
+     * <p>
+     * 对于用户传入参数会做必要检查,包括:
+     *
+     * <pre>
+     *     1、忽略多余的参数
+     *     2、参数不够补齐默认值
+     *     3、传入参数为null,但是目标参数类型为原始类型,做转换
+     * </pre>
+     *
+     * @param <T>    返回对象类型
+     * @param obj    对象,如果执行静态方法,此值为<code>null</code>
+     * @param method 方法(对象方法或static方法都可)
+     * @param args   参数对象
+     * @return 结果
+     * @throws UtilException 一些列异常的包装
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T invoke(Object obj, Method method, Object... args) throws UtilException {
+        setAccessible(method);
+
+        // 检查用户传入参数:
+        // 1、忽略多余的参数
+        // 2、参数不够补齐默认值
+        // 3、通过NullWrapperBean传递的参数,会直接赋值null
+        // 4、传入参数为null,但是目标参数类型为原始类型,做转换
+        // 5、传入参数类型不对应,尝试转换类型
+        final Class<?>[] parameterTypes = method.getParameterTypes();
+        final Object[] actualArgs = new Object[parameterTypes.length];
+        if (null != args) {
+            for (int i = 0; i < actualArgs.length; i++) {
+                if (i >= args.length || null == args[i]) {
+                    // 越界或者空值
+                    actualArgs[i] = ClassUtil.getDefaultValue(parameterTypes[i]);
+                } else if (args[i] instanceof NullWrapperBean) {
+                    //如果是通过NullWrapperBean传递的null参数,直接赋值null
+                    actualArgs[i] = null;
+                } else if (!parameterTypes[i].isAssignableFrom(args[i].getClass())) {
+                    //对于类型不同的字段,尝试转换,转换失败则使用原对象类型
+                    final Object targetValue = Convert.convert(parameterTypes[i], args[i]);
+                    if (null != targetValue) {
+                        actualArgs[i] = targetValue;
+                    }
+                } else {
+                    actualArgs[i] = args[i];
+                }
+            }
+        }
+
+        try {
+            return (T) method.invoke(ClassUtil.isStatic(method) ? null : obj, actualArgs);
+        } catch (Exception e) {
+            throw new UtilException(e);
+        }
+    }
+
+    /**
+     * 执行对象中指定方法
+     * 如果需要传递的参数为null,请使用NullWrapperBean来传递,不然会丢失类型信息
+     *
+     * @param <T>        返回对象类型
+     * @param obj        方法所在对象
+     * @param methodName 方法名
+     * @param args       参数列表
+     * @return 执行结果
+     * @throws UtilException IllegalAccessException包装
+     * @see NullWrapperBean
+     * @since 3.1.2
+     */
+    public static <T> T invoke(Object obj, String methodName, Object... args) throws UtilException {
+        final Method method = getMethodOfObj(obj, methodName, args);
+        if (null == method) {
+            throw new UtilException(StrUtil.format("No such method: [{}]", methodName));
+        }
+        return invoke(obj, method, args);
+    }
 
 	/**
 	 * 设置方法为可访问(私有方法可以被外部调用)