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);
+ }
/**
* 设置方法为可访问(私有方法可以被外部调用)