invoke support null type

This commit is contained in:
Looly 2020-11-08 18:01:24 +08:00
parent e295779330
commit b8adadda38
6 changed files with 158 additions and 108 deletions

View File

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

View File

@ -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;
}
}

View File

@ -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;
}
/**
* 指定类是否与给定的类名相同

View File

@ -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);
/**
* 执行方法
*
* <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];
}
}
}
// 检查用户传入参数
// 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 <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);
}
/**
* 执行对象中指定方法
* 如果需要传递的参数为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);
}
/**
* 设置方法为可访问私有方法可以被外部调用

View File

@ -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;
}

View File

@ -15,15 +15,27 @@ 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 {
validator = Validation.buildDefaultValidatorFactory().getValidator();
}
/**
* 获取原生{@link Validator} 对象
*
* @return {@link Validator} 对象
*/
public static Validator getValidator() {
return validator;
}
/**
* 校验对象
*