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();