diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ea43ec0b..ad9219221 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ * 【core 】 新增Hash接口,HashXXX继承此接口 * 【core 】 ZipUtil增加append方法(pr#441@Gitee) * 【core 】 CollUtil增加重载(issue#I4E9FS@Gitee) +* 【core 】 CopyOptions新增setFieldValueEditor(issue#I4E08T@Gitee) ### 🐞Bug修复 * 【core 】 修复CollUtil.isEqualList两个null返回错误问题(issue#1885@Github) diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/BeanUtil.java b/hutool-core/src/main/java/cn/hutool/core/bean/BeanUtil.java index 84b99c239..796124648 100644 --- a/hutool-core/src/main/java/cn/hutool/core/bean/BeanUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/BeanUtil.java @@ -664,6 +664,32 @@ public class BeanUtil { ).copy(); } + /** + * 对象转Map
+ * 通过自定义{@link CopyOptions} 完成抓换选项,以便实现: + * + *
+	 * 1. 字段筛选,可以去除不需要的字段
+	 * 2. 字段变换,例如实现驼峰转下划线
+	 * 3. 自定义字段前缀或后缀等等
+	 * 4. 字段值处理
+	 * ...
+	 * 
+ * + * @param bean bean对象 + * @param targetMap 目标的Map + * @param copyOptions 拷贝选项 + * @return Map + * @since 5.7.15 + */ + public static Map beanToMap(Object bean, Map targetMap, CopyOptions copyOptions) { + if (null == bean) { + return null; + } + + return BeanCopier.create(bean, targetMap, copyOptions).copy(); + } + // --------------------------------------------------------------------------------------------- copyProperties /** diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanCopier.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanCopier.java index fc6c3947d..bcfae58a1 100644 --- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanCopier.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanCopier.java @@ -191,6 +191,10 @@ public class BeanCopier implements Copier, Serializable { if(null != copyOptions.propertiesFilter && false == copyOptions.propertiesFilter.test(prop.getField(), value)) { return; } + + // since 5.7.15 + value = copyOptions.editFieldValue(key, value); + if ((null == value && copyOptions.ignoreNullValue) || bean == value) { // 当允许跳过空时,跳过 //值不能为bean本身,防止循环引用,此类也跳过 @@ -257,6 +261,9 @@ public class BeanCopier implements Copier, Serializable { return; } + // since 5.7.15 + value = copyOptions.editFieldValue(providerKey, value); + if ((null == value && copyOptions.ignoreNullValue) || bean == value) { // 当允许跳过空时,跳过 // 值不能为bean本身,防止循环引用 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 502ea4846..4cab13809 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 @@ -7,6 +7,7 @@ import cn.hutool.core.util.ObjectUtil; import java.io.Serializable; import java.lang.reflect.Field; import java.util.Map; +import java.util.function.BiFunction; import java.util.function.BiPredicate; /** @@ -57,6 +58,10 @@ public class CopyOptions implements Serializable { * 字段属性编辑器,用于自定义属性转换规则,例如驼峰转下划线等 */ protected Editor fieldNameEditor; + /** + * 字段属性值编辑器,用于自定义属性值转换规则,例如null转""等 + */ + protected BiFunction fieldValueEditor; /** * 是否支持transient关键字修饰和@Transient注解,如果支持,被修饰的字段或方法对应的字段将被忽略。 */ @@ -224,6 +229,30 @@ public class CopyOptions implements Serializable { return this; } + /** + * 设置字段属性值编辑器,用于自定义属性值转换规则,例如null转""等
+ * + * @param fieldValueEditor 字段属性值编辑器,用于自定义属性值转换规则,例如null转""等 + * @return CopyOptions + * @since 5.7.15 + */ + public CopyOptions setFieldValueEditor(BiFunction fieldValueEditor) { + this.fieldValueEditor = fieldValueEditor; + return this; + } + + /** + * 转换字段名为编辑后的字段名 + * + * @param fieldName 字段名 + * @return 编辑后的字段名 + * @since 5.7.15 + */ + protected Object editFieldValue(String fieldName, Object fieldValue) { + return (null != this.fieldValueEditor) ? + this.fieldValueEditor.apply(fieldName, fieldValue) : fieldValue; + } + /** * 是否支持transient关键字修饰和@Transient注解,如果支持,被修饰的字段或方法对应的字段将被忽略。 * @@ -251,12 +280,12 @@ public class CopyOptions implements Serializable { * 当非反向,则根据源字段名获取目标字段名,反之根据目标字段名获取源字段名。 * * @param fieldName 字段名 - * @param reversed 是否反向映射 + * @param reversed 是否反向映射 * @return 映射后的字段名 */ - protected String getMappedFieldName(String fieldName, boolean reversed){ + protected String getMappedFieldName(String fieldName, boolean reversed) { Map mapping = reversed ? getReversedMapping() : this.fieldMapping; - if(MapUtil.isEmpty(mapping)){ + if (MapUtil.isEmpty(mapping)) { return fieldName; } return ObjectUtil.defaultIfNull(mapping.get(fieldName), fieldName); @@ -264,11 +293,12 @@ public class CopyOptions implements Serializable { /** * 转换字段名为编辑后的字段名 + * * @param fieldName 字段名 * @return 编辑后的字段名 * @since 5.4.2 */ - protected String editFieldName(String fieldName){ + protected String editFieldName(String fieldName) { return (null != this.fieldNameEditor) ? this.fieldNameEditor.edit(fieldName) : fieldName; } @@ -279,10 +309,10 @@ public class CopyOptions implements Serializable { * @since 4.1.10 */ private Map getReversedMapping() { - if(null == this.fieldMapping){ + if (null == this.fieldMapping) { return null; } - if(null == this.reversedFieldMapping){ + if (null == this.reversedFieldMapping) { reversedFieldMapping = MapUtil.reverse(this.fieldMapping); } return reversedFieldMapping; diff --git a/hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java index 526e8bbca..d05bc13b0 100644 --- a/hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java @@ -197,6 +197,19 @@ public class BeanUtilTest { Assert.assertEquals("sub名字", map.get("sub_name")); } + @Test + public void beanToMapWithValueEditTest() { + SubPerson person = new SubPerson(); + person.setAge(14); + person.setOpenid("11213232"); + person.setName("测试A11"); + person.setSubName("sub名字"); + + Map map = BeanUtil.beanToMap(person, new LinkedHashMap<>(), + CopyOptions.create().setFieldValueEditor((key, value) -> key + "_" + value)); + Assert.assertEquals("subName_sub名字", map.get("subName")); + } + @Test public void beanToMapWithAliasTest() { SubPersonWithAlias person = new SubPersonWithAlias();