Browse Source

invoke support null type

Looly 5 years ago
parent
commit
b8adadda38

+ 1 - 0
CHANGELOG.md

@@ -9,6 +9,7 @@
 * 【core   】     NumberUtil.parseInt等支持123,2.00这类数字(issue#I23ORQ@Gitee)
 * 【core   】     增加ArrayUtil.isSub、indexOfSub、lastIndexOfSub方法(issue#I23O1K@Gitee)
 * 【extra  】     增加ValidationUtil(pr#207@Gitee)
+* 【core   】     反射调用支持传递参数的值为null(pr#1205@Github)
 
 ### Bug修复
 * 【core   】     修复DateUtil.current使用System.nanoTime的问题(issue#1198@Github)

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

@@ -2,19 +2,28 @@ package cn.hutool.core.bean;
 
 /**
  * 为了解决反射过程中,需要传递null参数,但是会丢失参数类型而设立的包装类
+ *
+ * @param <T> Null值对应的类型
+ * @author Lillls
+ * @since 5.5.0
  */
-public class NullWrapperBean {
+public class NullWrapperBean<T> {
 
-    private final Class<?> mClasses;
+	private final Class<T> clazz;
 
-    /**
-     * @param classes null的类型
-     */
-    public NullWrapperBean(Class<?> classes) {
-        this.mClasses = classes;
-    }
+	/**
+	 * @param clazz null的类型
+	 */
+	public NullWrapperBean(Class<T> clazz) {
+		this.clazz = clazz;
+	}
 
-    public Class<?> getClasses() {
-        return mClasses;
-    }
+	/**
+	 * 获取null值对应的类型
+	 *
+	 * @return 类型
+	 */
+	public Class<T> getWrappedClass() {
+		return clazz;
+	}
 }

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

@@ -140,21 +140,22 @@ 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];
-            if (obj instanceof NullWrapperBean) {
-                classes[i] = ((NullWrapperBean) obj).getClasses();
-            } else if (null == obj) {
-                classes[i] = Object.class;
-            } else {
-                classes[i] = 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) {
+				// 自定义null值的参数类型
+				classes[i] = ((NullWrapperBean<?>) obj).getWrappedClass();
+			} else if (null == obj) {
+				classes[i] = Object.class;
+			} else {
+				classes[i] = obj.getClass();
+			}
+		}
+		return classes;
+	}
 
 	/**
 	 * 指定类是否与给定的类名相同

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

@@ -149,7 +149,7 @@ public class ReflectUtil {
 	 */
 	public static Field getField(Class<?> beanClass, String name) throws SecurityException {
 		final Field[] fields = getFields(beanClass);
-		return ArrayUtil.firstMatch((field)->name.equals(getFieldName(field)), fields);
+		return ArrayUtil.firstMatch((field) -> name.equals(getFieldName(field)), fields);
 	}
 
 	/**
@@ -191,7 +191,7 @@ public class ReflectUtil {
 	 * 获得一个类中所有字段列表,直接反射获取,无缓存<br>
 	 * 如果子类与父类中存在同名字段,则这两个字段同时存在,子类字段在前,父类字段在后。
 	 *
-	 * @param beanClass           类
+	 * @param beanClass            
 	 * @param withSuperClassFields 是否包括父类的字段列表
 	 * @return 字段列表
 	 * @throws SecurityException 安全检查异常
@@ -865,84 +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、通过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);
-    }
+	/**
+	 * 执行方法
+	 *
+	 * <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 (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);
+		}
+	}
+
+	/**
+	 * 执行对象中指定方法
+	 * 如果需要传递的参数为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);
+	}
 
 	/**
 	 * 设置方法为可访问(私有方法可以被外部调用)

+ 31 - 4
hutool-extra/src/main/java/cn/hutool/extra/validation/BeanValidationResult.java

@@ -7,10 +7,9 @@ import java.util.List;
  * bean 校验结果
  *
  * @author chengqiang
+ * @since 5.5.0
  */
-
 public class BeanValidationResult {
-
 	/**
 	 * 校验是否成功
 	 */
@@ -25,29 +24,57 @@ public class BeanValidationResult {
 	 *
 	 * @param success 是否验证成功
 	 */
-	public BeanValidationResult(boolean success){
+	public BeanValidationResult(boolean success) {
 		this.success = success;
 	}
 
+	/**
+	 * 是否验证通过
+	 *
+	 * @return 是否验证通过
+	 */
 	public boolean isSuccess() {
 		return success;
 	}
 
+	/**
+	 * 设置是否通过
+	 *
+	 * @param success 是否通过
+	 * @return this
+	 */
 	public BeanValidationResult setSuccess(boolean success) {
 		this.success = success;
 		return this;
 	}
 
+	/**
+	 * 获取错误信息列表
+	 *
+	 * @return 错误信息列表
+	 */
 	public List<ErrorMessage> getErrorMessages() {
 		return errorMessages;
 	}
 
+	/**
+	 * 设置错误信息列表
+	 *
+	 * @param errorMessages 错误信息列表
+	 * @return this
+	 */
 	public BeanValidationResult setErrorMessages(List<ErrorMessage> errorMessages) {
 		this.errorMessages = errorMessages;
 		return this;
 	}
 
-	public BeanValidationResult addErrorMessage(ErrorMessage errorMessage){
+	/**
+	 * 增加错误信息
+	 *
+	 * @param errorMessage 错误信息
+	 * @return this
+	 */
+	public BeanValidationResult addErrorMessage(ErrorMessage errorMessage) {
 		this.errorMessages.add(errorMessage);
 		return this;
 	}

+ 13 - 1
hutool-extra/src/main/java/cn/hutool/extra/validation/ValidationUtil.java

@@ -15,9 +15,12 @@ import java.util.Set;
  * <p>注意:hibernate-validator还依赖了javax.el,需自行引入。</p>
  *
  * @author chengqiang
+ * @since 5.5.0
  */
 public class ValidationUtil {
-
+	/**
+	 * 默认{@link Validator} 对象
+	 */
 	private static final Validator validator;
 
 	static {
@@ -25,6 +28,15 @@ public class ValidationUtil {
 	}
 
 	/**
+	 * 获取原生{@link Validator} 对象
+	 *
+	 * @return {@link Validator} 对象
+	 */
+	public static Validator getValidator() {
+		return validator;
+	}
+
+	/**
 	 * 校验对象
 	 *
 	 * @param <T>    Bean类型