From 8181519c0d2cf4b813e07cc786b8ba65710e6531 Mon Sep 17 00:00:00 2001 From: lixiaoyu08 Date: Thu, 5 Nov 2020 21:23:26 +0800 Subject: [PATCH] =?UTF-8?q?[=E6=96=B0=E7=89=B9=E6=80=A7]=E5=8F=8D=E5=B0=84?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E6=94=AF=E6=8C=81=E4=BC=A0=E9=80=92=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E7=9A=84=E5=80=BC=E4=B8=BAnull?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加对null参数传递的支持,在传递null参数保持类型信息不丢失 --- .../cn/hutool/core/bean/NullWrapperBean.java | 20 +++ .../java/cn/hutool/core/util/ClassUtil.java | 25 +-- .../java/cn/hutool/core/util/ReflectUtil.java | 145 +++++++++--------- 3 files changed, 112 insertions(+), 78 deletions(-) create mode 100644 hutool-core/src/main/java/cn/hutool/core/bean/NullWrapperBean.java diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/NullWrapperBean.java b/hutool-core/src/main/java/cn/hutool/core/bean/NullWrapperBean.java new file mode 100644 index 000000000..053663a04 --- /dev/null +++ b/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; + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ClassUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ClassUtil.java index 2b190f58e..c3e3f7930 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ClassUtil.java +++ b/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; + } /** * 指定类是否与给定的类名相同 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 b59bbebcc..83362163f 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 @@ -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); } - /** - * 执行方法 - * - *

- * 对于用户传入参数会做必要检查,包括: - * - *

-	 *     1、忽略多余的参数
-	 *     2、参数不够补齐默认值
-	 *     3、传入参数为null,但是目标参数类型为原始类型,做转换
-	 * 
- * - * @param 返回对象类型 - * @param obj 对象,如果执行静态方法,此值为null - * @param method 方法(对象方法或static方法都可) - * @param args 参数对象 - * @return 结果 - * @throws UtilException 一些列异常的包装 - */ - @SuppressWarnings("unchecked") - public static T invoke(Object obj, Method method, Object... args) throws UtilException { - setAccessible(method); + /** + * 执行方法 + * + *

+ * 对于用户传入参数会做必要检查,包括: + * + *

+     *     1、忽略多余的参数
+     *     2、参数不够补齐默认值
+     *     3、传入参数为null,但是目标参数类型为原始类型,做转换
+     * 
+ * + * @param 返回对象类型 + * @param obj 对象,如果执行静态方法,此值为null + * @param method 方法(对象方法或static方法都可) + * @param args 参数对象 + * @return 结果 + * @throws UtilException 一些列异常的包装 + */ + @SuppressWarnings("unchecked") + public static 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]; - } - } - } + // 检查用户传入参数: + // 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); - } - } + try { + return (T) method.invoke(ClassUtil.isStatic(method) ? null : obj, actualArgs); + } catch (Exception e) { + throw new UtilException(e); + } + } - /** - * 执行对象中指定方法 - * - * @param 返回对象类型 - * @param obj 方法所在对象 - * @param methodName 方法名 - * @param args 参数列表 - * @return 执行结果 - * @throws UtilException IllegalAccessException包装 - * @since 3.1.2 - */ - public static 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); - } + /** + * 执行对象中指定方法 + * 如果需要传递的参数为null,请使用NullWrapperBean来传递,不然会丢失类型信息 + * + * @param 返回对象类型 + * @param obj 方法所在对象 + * @param methodName 方法名 + * @param args 参数列表 + * @return 执行结果 + * @throws UtilException IllegalAccessException包装 + * @see NullWrapperBean + * @since 3.1.2 + */ + public static 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); + } /** * 设置方法为可访问(私有方法可以被外部调用)