diff --git a/CHANGELOG.md b/CHANGELOG.md index e46170c6d..8a2b2a531 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ### 🐣新特性 * 【core 】 WatchServer新增通过Path获取WatchKey方法(pr#1145@Gitee) +* 【core 】 CopyOptions中增加setAutoTransCamelCase方法(issue#3452@Github) ### 🐞Bug修复 * 【core 】 修复StrJoin当append内容后调用length()会出现空指针问题(issue#3444@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 84cae5a15..25ada700c 100755 --- a/hutool-core/src/main/java/cn/hutool/core/bean/BeanUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/BeanUtil.java @@ -408,7 +408,9 @@ public class BeanUtil { * @param isToCamelCase 是否将Map中的下划线风格key转换为驼峰风格 * @param copyOptions 转Bean选项 * @return Bean + * @deprecated isToCamelCase参数无效,请使用 {@link #toBean(Object, Class, CopyOptions)} */ + @Deprecated public static T mapToBean(Map map, Class beanClass, boolean isToCamelCase, CopyOptions copyOptions) { return fillBeanWithMap(map, ReflectUtil.newInstanceIfPossible(beanClass), isToCamelCase, copyOptions); } @@ -437,7 +439,9 @@ public class BeanUtil { * @param isToCamelCase 是否将下划线模式转换为驼峰模式 * @param isIgnoreError 是否忽略注入错误 * @return Bean + * @deprecated isToCamelCase参数无效,请使用{@link #fillBeanWithMap(Map, Object, boolean)} */ + @Deprecated public static T fillBeanWithMap(Map map, T bean, boolean isToCamelCase, boolean isIgnoreError) { return fillBeanWithMap(map, bean, isToCamelCase, CopyOptions.create().setIgnoreError(isIgnoreError)); } @@ -465,7 +469,11 @@ public class BeanUtil { * @return Bean */ public static T fillBeanWithMap(Map map, T bean, CopyOptions copyOptions) { - return fillBeanWithMap(map, bean, false, copyOptions); + if (MapUtil.isEmpty(map)) { + return bean; + } + copyProperties(map, bean, copyOptions); + return bean; } /** @@ -478,14 +486,18 @@ public class BeanUtil { * @param copyOptions 属性复制选项 {@link CopyOptions} * @return Bean * @since 3.3.1 + * @deprecated isToCamelCase参数无效,请使用{@link #fillBeanWithMap(Map, Object, CopyOptions)} */ + @Deprecated public static T fillBeanWithMap(Map map, T bean, boolean isToCamelCase, CopyOptions copyOptions) { if (MapUtil.isEmpty(map)) { return bean; } - if (isToCamelCase) { - map = MapUtil.toCamelCaseMap(map); - } + + // issue#3452,参数无效,MapToBeanCopier中已经有转驼峰逻辑 +// if (isToCamelCase) { +// map = MapUtil.toCamelCaseMap(map); +// } copyProperties(map, bean, copyOptions); return bean; } 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 51250433c..804b56176 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 @@ -66,7 +66,7 @@ public class BeanToBeanCopier extends AbsCopier { } // 检查目标字段可写性 - final PropDesc tDesc = targetPropDescMap.get(sFieldName); + final PropDesc tDesc = this.copyOptions.findPropDesc(targetPropDescMap, sFieldName); if (null == tDesc || false == tDesc.isWritable(this.copyOptions.transientSupport)) { // 字段不可写,跳过之 return; 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 d6224880a..4cb924893 100755 --- 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,6 @@ package cn.hutool.core.bean.copier; +import cn.hutool.core.bean.PropDesc; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.TypeConverter; @@ -70,6 +71,11 @@ public class CopyOptions implements Serializable { */ protected boolean override = true; + /** + * 是否自动转换为驼峰方式 + */ + protected boolean autoTransCamelCase = true; + /** * 源对象和目标对象都是 {@code Map} 时, 需要忽略的源对象 {@code Map} key */ @@ -321,6 +327,19 @@ public class CopyOptions implements Serializable { return this; } + /** + * 设置是否自动转换为驼峰方式
+ * 一般用于map转bean和bean转bean出现非驼峰格式时,在尝试转换失败的情况下,是否二次检查转为驼峰匹配 + * + * @param autoTransCamelCase 是否自动转换为驼峰方式 + * @return this + * @since 5.8.25 + */ + public CopyOptions setAutoTransCamelCase(final boolean autoTransCamelCase) { + this.autoTransCamelCase = autoTransCamelCase; + return this; + } + /** * 设置自定义类型转换器,默认使用全局万能转换器转换。 * @@ -391,4 +410,25 @@ public class CopyOptions implements Serializable { return false == this.ignoreKeySet.contains(key); } + + /** + * 查找Map对应Bean的名称
+ * 尝试原名称、转驼峰名称、isXxx去掉is的名称 + * + * @param targetPropDescMap 目标bean的属性描述Map + * @param sKeyStr 键或字段名 + * @return {@link PropDesc} + */ + protected PropDesc findPropDesc(final Map targetPropDescMap, final String sKeyStr) { + PropDesc propDesc = targetPropDescMap.get(sKeyStr); + // 转驼峰尝试查找 + if (null == propDesc && this.autoTransCamelCase) { + final String camelCaseKey = StrUtil.toCamelCase(sKeyStr); + if (!StrUtil.equals(sKeyStr, camelCaseKey)) { + // 只有转换为驼峰后与原key不同才重复查询,相同说明本身就是驼峰,不需要二次查询 + propDesc = targetPropDescMap.get(camelCaseKey); + } + } + return propDesc; + } } 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 47d08ded4..7f0a98234 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 @@ -73,7 +73,7 @@ public class MapToBeanCopier extends AbsCopier, T> { } // 检查目标字段可写性 - final PropDesc tDesc = findPropDesc(targetPropDescMap, sKeyStr); + final PropDesc tDesc = this.copyOptions.findPropDesc(targetPropDescMap, sKeyStr); if (null == tDesc || false == tDesc.isWritable(this.copyOptions.transientSupport)) { // 字段不可写,跳过之 return; @@ -96,24 +96,4 @@ public class MapToBeanCopier extends AbsCopier, T> { }); return this.target; } - - /** - * 查找Map对应Bean的名称
- * 尝试原名称、转驼峰名称、isXxx去掉is的名称 - * - * @param targetPropDescMap 目标bean的属性描述Map - * @param sKeyStr 键或字段名 - * @return {@link PropDesc} - */ - private PropDesc findPropDesc(Map targetPropDescMap, String sKeyStr){ - PropDesc propDesc = targetPropDescMap.get(sKeyStr); - if(null != propDesc){ - return propDesc; - } - - // 转驼峰尝试查找 - sKeyStr = StrUtil.toCamelCase(sKeyStr); - propDesc = targetPropDescMap.get(sKeyStr); - return propDesc; - } } diff --git a/hutool-core/src/test/java/cn/hutool/core/bean/Issue3452Test.java b/hutool-core/src/test/java/cn/hutool/core/bean/Issue3452Test.java new file mode 100644 index 000000000..6716668a5 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/bean/Issue3452Test.java @@ -0,0 +1,29 @@ +package cn.hutool.core.bean; + +import cn.hutool.core.bean.copier.CopyOptions; +import lombok.Data; +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +public class Issue3452Test { + + @Test + public void fillBeanWithMapTest() { + final Map properties = new HashMap<>(); + properties.put("name", "JohnDoe"); + properties.put("user_age", 25); + final User user = BeanUtil.fillBeanWithMap( + properties, new User(), CopyOptions.create()); + Assert.assertEquals("JohnDoe", user.getName()); + Assert.assertEquals(25, user.getUserAge()); + } + + @Data + static class User { + private String name; + private int userAge; + } +}