From 11d7d8c0921cbc1b19084de0fff3fc9f889fe75d Mon Sep 17 00:00:00 2001 From: Looly Date: Wed, 13 Apr 2022 23:28:42 +0800 Subject: [PATCH] add TypeConverter --- CHANGELOG.md | 1 + .../core/bean/copier/BeanToBeanCopier.java | 4 +- .../core/bean/copier/BeanToMapCopier.java | 4 +- .../hutool/core/bean/copier/CopyOptions.java | 42 +++++++++++++++++-- .../core/bean/copier/MapToBeanCopier.java | 4 +- .../core/bean/copier/MapToMapCopier.java | 4 +- .../cn/hutool/core/convert/TypeConverter.java | 24 +++++++++++ 7 files changed, 72 insertions(+), 11 deletions(-) create mode 100644 hutool-core/src/main/java/cn/hutool/core/convert/TypeConverter.java diff --git a/CHANGELOG.md b/CHANGELOG.md index a52b71e29..d8b6dd8ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ * 【core 】 增加Pid,以便获取单例pid * 【core 】 Img增加全覆盖水印pressTextFull(pr#595@Gitee) * 【core 】 ByteUtil.numberToBytes增加Byte判断(issue#2252@Github) +* 【core 】 CopyOptions添加converter,可以自定义非全局类型转换 ### 🐞Bug修复 * 【core 】 修复UserAgentUtil识别Linux出错(issue#I50YGY@Gitee) diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToBeanCopier.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToBeanCopier.java index c6abd1f9b..e91c1914f 100755 --- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToBeanCopier.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToBeanCopier.java @@ -2,7 +2,6 @@ package cn.hutool.core.bean.copier; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.PropDesc; -import cn.hutool.core.convert.Convert; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.TypeUtil; @@ -75,7 +74,8 @@ public class BeanToBeanCopier extends AbsCopier { // 获取目标字段真实类型并转换源值 final Type fieldType = TypeUtil.getActualType(this.targetType, tDesc.getFieldType()); - sValue = Convert.convertWithCheck(fieldType, sValue, null, this.copyOptions.ignoreError); + //sValue = Convert.convertWithCheck(fieldType, sValue, null, this.copyOptions.ignoreError); + sValue = this.copyOptions.convertField(fieldType, sValue); sValue = copyOptions.editFieldValue(sFieldName, sValue); // 目标赋值 diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToMapCopier.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToMapCopier.java index 52a4bf8a3..36a6d1f4b 100755 --- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToMapCopier.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanToMapCopier.java @@ -2,7 +2,6 @@ package cn.hutool.core.bean.copier; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.PropDesc; -import cn.hutool.core.convert.Convert; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.TypeUtil; @@ -67,7 +66,8 @@ public class BeanToMapCopier extends AbsCopier { // 获取目标值真实类型并转换源值 final Type[] typeArguments = TypeUtil.getTypeArguments(this.targetType); if(null != typeArguments){ - sValue = Convert.convertWithCheck(typeArguments[1], sValue, null, this.copyOptions.ignoreError); + //sValue = Convert.convertWithCheck(typeArguments[1], sValue, null, this.copyOptions.ignoreError); + sValue = this.copyOptions.convertField(typeArguments[1], sValue); sValue = copyOptions.editFieldValue(sFieldName, sValue); } diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/CopyOptions.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/CopyOptions.java index 0395bec04..2a48a38fb 100644 --- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/CopyOptions.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/CopyOptions.java @@ -1,5 +1,7 @@ package cn.hutool.core.bean.copier; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.convert.TypeConverter; import cn.hutool.core.lang.Editor; import cn.hutool.core.lang.func.Func1; import cn.hutool.core.lang.func.LambdaUtil; @@ -7,6 +9,7 @@ import cn.hutool.core.util.ArrayUtil; import java.io.Serializable; import java.lang.reflect.Field; +import java.lang.reflect.Type; import java.util.Map; import java.util.Set; import java.util.function.BiFunction; @@ -64,7 +67,14 @@ public class CopyOptions implements Serializable { */ protected boolean override = true; + /** + * 自定义类型转换器,默认使用全局万能转换器转换 + */ + protected TypeConverter converter = (type, value) -> + Convert.convertWithCheck(type, value, null, ignoreError); + //region create + /** * 创建拷贝选项 * @@ -164,8 +174,8 @@ public class CopyOptions implements Serializable { /** * 设置忽略的目标对象中属性列表,设置一个属性列表,不拷贝这些属性值,Lambda方式 * - * @param

参数类型 - * @param 返回值类型 + * @param

参数类型 + * @param 返回值类型 * @param funcs 忽略的目标对象中属性列表,设置一个属性列表,不拷贝这些属性值 * @return CopyOptions * @since 5.8.0 @@ -225,7 +235,7 @@ public class CopyOptions implements Serializable { * @return CopyOptions */ public CopyOptions setFieldMapping(Map fieldMapping) { - return setFieldNameEditor((key-> fieldMapping.getOrDefault(key, key))); + return setFieldNameEditor((key -> fieldMapping.getOrDefault(key, key))); } /** @@ -291,6 +301,32 @@ public class CopyOptions implements Serializable { return this; } + /** + * 设置自定义类型转换器,默认使用全局万能转换器转换。 + * + * @param converter 转换器 + * @return this + * @since 5.8.0 + */ + public CopyOptions setConverter(TypeConverter converter) { + this.converter = converter; + return this; + } + + /** + * 使用自定义转换器转换字段值
+ * 如果自定义转换器为{@code null},则返回原值。 + * + * @param targetType 目标类型 + * @param fieldValue 字段值 + * @return 编辑后的字段值 + * @since 5.8.0 + */ + protected Object convertField(Type targetType, Object fieldValue) { + return (null != this.converter) ? + this.converter.convert(targetType, fieldValue) : fieldValue; + } + /** * 转换字段名为编辑后的字段名 * diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/MapToBeanCopier.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/MapToBeanCopier.java index 43da5311a..349bf7d6c 100755 --- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/MapToBeanCopier.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/MapToBeanCopier.java @@ -2,7 +2,6 @@ package cn.hutool.core.bean.copier; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.PropDesc; -import cn.hutool.core.convert.Convert; import cn.hutool.core.lang.Assert; import cn.hutool.core.map.CaseInsensitiveMap; import cn.hutool.core.map.MapWrapper; @@ -83,7 +82,8 @@ public class MapToBeanCopier extends AbsCopier, T> { // 获取目标字段真实类型并转换源值 final Type fieldType = TypeUtil.getActualType(this.targetType, tDesc.getFieldType()); - Object newValue = Convert.convertWithCheck(fieldType, sValue, null, this.copyOptions.ignoreError); + //Object newValue = Convert.convertWithCheck(fieldType, sValue, null, this.copyOptions.ignoreError); + Object newValue = this.copyOptions.convertField(fieldType, sValue); newValue = copyOptions.editFieldValue(sKeyStr, newValue); // 目标赋值 diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/MapToMapCopier.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/MapToMapCopier.java index e5bb62bf9..e32eaf2e0 100755 --- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/MapToMapCopier.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/MapToMapCopier.java @@ -1,6 +1,5 @@ package cn.hutool.core.bean.copier; -import cn.hutool.core.convert.Convert; import cn.hutool.core.util.TypeUtil; import java.lang.reflect.Type; @@ -53,7 +52,8 @@ public class MapToMapCopier extends AbsCopier { // 获取目标值真实类型并转换源值 final Type[] typeArguments = TypeUtil.getTypeArguments(this.targetType); if(null != typeArguments){ - sValue = Convert.convertWithCheck(typeArguments[1], sValue, null, this.copyOptions.ignoreError); + //sValue = Convert.convertWithCheck(typeArguments[1], sValue, null, this.copyOptions.ignoreError); + sValue = this.copyOptions.convertField(typeArguments[1], sValue); sValue = copyOptions.editFieldValue(sKeyStr, sValue); } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/TypeConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/TypeConverter.java new file mode 100644 index 000000000..b72acd7f6 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/convert/TypeConverter.java @@ -0,0 +1,24 @@ +package cn.hutool.core.convert; + +import java.lang.reflect.Type; + +/** + * 类型转换接口函数,根据给定的值和目标类型,由用户自定义转换规则。 + * + * @author looly + * @since 5.8.0 + */ +@FunctionalInterface +public interface TypeConverter { + + /** + * 转换为指定类型
+ * 如果类型无法确定,将读取默认值的类型做为目标类型 + * + * @param targetType 目标Type,非泛型类使用 + * @param value 原始值 + * @return 转换后的值 + * @throws IllegalArgumentException 无法确定目标类型,且默认值为{@code null},无法确定类型 + */ + Object convert(Type targetType, Object value); +}