From b8adadda3813b81a87142bdd0b2a66f6755f16b8 Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 8 Nov 2020 18:01:24 +0800 Subject: [PATCH] invoke support null type --- CHANGELOG.md | 1 + .../cn/hutool/core/bean/NullWrapperBean.java | 31 ++-- .../java/cn/hutool/core/util/ClassUtil.java | 31 ++-- .../java/cn/hutool/core/util/ReflectUtil.java | 154 +++++++++--------- .../validation/BeanValidationResult.java | 35 +++- .../extra/validation/ValidationUtil.java | 14 +- 6 files changed, 158 insertions(+), 108 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd625227d..4b039fdfe 100644 --- a/CHANGELOG.md +++ b/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) 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 index 053663a04..c94d4fa6f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/bean/NullWrapperBean.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/NullWrapperBean.java @@ -2,19 +2,28 @@ package cn.hutool.core.bean; /** * 为了解决反射过程中,需要传递null参数,但是会丢失参数类型而设立的包装类 + * + * @param Null值对应的类型 + * @author Lillls + * @since 5.5.0 */ -public class NullWrapperBean { +public class NullWrapperBean { - private final Class mClasses; + private final Class clazz; - /** - * @param classes null的类型 - */ - public NullWrapperBean(Class classes) { - this.mClasses = classes; - } + /** + * @param clazz null的类型 + */ + public NullWrapperBean(Class clazz) { + this.clazz = clazz; + } - public Class getClasses() { - return mClasses; - } + /** + * 获取null值对应的类型 + * + * @return 类型 + */ + public Class getWrappedClass() { + return clazz; + } } 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 c3e3f7930..4b3fa4717 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 @@ -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; + } /** * 指定类是否与给定的类名相同 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 83362163f..48f116ea1 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 @@ -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 { * 获得一个类中所有字段列表,直接反射获取,无缓存
* 如果子类与父类中存在同名字段,则这两个字段同时存在,子类字段在前,父类字段在后。 * - * @param beanClass 类 + * @param beanClass 类 * @param withSuperClassFields 是否包括父类的字段列表 * @return 字段列表 * @throws SecurityException 安全检查异常 @@ -865,84 +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、通过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]; - } - } - } + // 检查用户传入参数: + // 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); - } - } + try { + return (T) method.invoke(ClassUtil.isStatic(method) ? null : obj, actualArgs); + } catch (Exception e) { + throw new UtilException(e); + } + } - /** - * 执行对象中指定方法 - * 如果需要传递的参数为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); - } + /** + * 执行对象中指定方法 + * 如果需要传递的参数为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); + } /** * 设置方法为可访问(私有方法可以被外部调用) diff --git a/hutool-extra/src/main/java/cn/hutool/extra/validation/BeanValidationResult.java b/hutool-extra/src/main/java/cn/hutool/extra/validation/BeanValidationResult.java index 2853c6276..73e87eb61 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/validation/BeanValidationResult.java +++ b/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 getErrorMessages() { return errorMessages; } + /** + * 设置错误信息列表 + * + * @param errorMessages 错误信息列表 + * @return this + */ public BeanValidationResult setErrorMessages(List 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; } diff --git a/hutool-extra/src/main/java/cn/hutool/extra/validation/ValidationUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/validation/ValidationUtil.java index 1118a5f1f..1bd9d291d 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/validation/ValidationUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/validation/ValidationUtil.java @@ -15,15 +15,27 @@ import java.util.Set; *

注意:hibernate-validator还依赖了javax.el,需自行引入。

* * @author chengqiang + * @since 5.5.0 */ public class ValidationUtil { - + /** + * 默认{@link Validator} 对象 + */ private static final Validator validator; static { validator = Validation.buildDefaultValidatorFactory().getValidator(); } + /** + * 获取原生{@link Validator} 对象 + * + * @return {@link Validator} 对象 + */ + public static Validator getValidator() { + return validator; + } + /** * 校验对象 *