mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-24 18:04:54 +08:00
修复BeanUtil.copyProperties中mapToMap时key被转为String问题
This commit is contained in:
parent
2fffc07c0f
commit
ca16ad9f1d
@ -373,12 +373,12 @@ public class BeanUtil {
|
||||
*/
|
||||
public static Map<String, Object> beanToMap(final Object bean, final String... properties) {
|
||||
int mapSize = 16;
|
||||
UnaryOperator<MutableEntry<String, Object>> editor = null;
|
||||
UnaryOperator<MutableEntry<Object, Object>> editor = null;
|
||||
if (ArrayUtil.isNotEmpty(properties)) {
|
||||
mapSize = properties.length;
|
||||
final Set<String> propertiesSet = SetUtil.of(properties);
|
||||
editor = entry -> {
|
||||
final String key = entry.getKey();
|
||||
final String key = StrUtil.toStringOrNull(entry.getKey());
|
||||
entry.setKey(propertiesSet.contains(key) ? key : null);
|
||||
return entry;
|
||||
};
|
||||
@ -413,13 +413,14 @@ public class BeanUtil {
|
||||
* @return Map
|
||||
* @since 3.2.3
|
||||
*/
|
||||
public static Map<String, Object> beanToMap(final Object bean, final Map<String, Object> targetMap, final boolean isToUnderlineCase, final boolean ignoreNullValue) {
|
||||
public static Map<String, Object> beanToMap(final Object bean, final Map<String, Object> targetMap,
|
||||
final boolean isToUnderlineCase, final boolean ignoreNullValue) {
|
||||
if (null == bean) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return beanToMap(bean, targetMap, ignoreNullValue, entry -> {
|
||||
final String key = entry.getKey();
|
||||
final String key = StrUtil.toStringOrNull(entry.getKey());
|
||||
entry.setKey(isToUnderlineCase ? StrUtil.toUnderlineCase(key) : key);
|
||||
return entry;
|
||||
});
|
||||
@ -442,8 +443,10 @@ public class BeanUtil {
|
||||
* @return Map
|
||||
* @since 4.0.5
|
||||
*/
|
||||
public static Map<String, Object> beanToMap(final Object bean, final Map<String, Object> targetMap,
|
||||
final boolean ignoreNullValue, final UnaryOperator<MutableEntry<String, Object>> keyEditor) {
|
||||
public static Map<String, Object> beanToMap(final Object bean,
|
||||
final Map<String, Object> targetMap,
|
||||
final boolean ignoreNullValue,
|
||||
final UnaryOperator<MutableEntry<Object, Object>> keyEditor) {
|
||||
if (null == bean) {
|
||||
return null;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import org.dromara.hutool.core.bean.PropDesc;
|
||||
import org.dromara.hutool.core.lang.Assert;
|
||||
import org.dromara.hutool.core.lang.mutable.MutableEntry;
|
||||
import org.dromara.hutool.core.reflect.TypeUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
@ -73,11 +74,11 @@ public class BeanToBeanCopier<S, T> extends AbsCopier<S, T> {
|
||||
}
|
||||
|
||||
// 编辑键值对
|
||||
final MutableEntry<String, Object> entry = copyOptions.editField(sFieldName, sValue);
|
||||
final MutableEntry<Object, Object> entry = copyOptions.editField(sFieldName, sValue);
|
||||
if(null == entry){
|
||||
return;
|
||||
}
|
||||
sFieldName = entry.getKey();
|
||||
sFieldName = StrUtil.toStringOrNull(entry.getKey());
|
||||
// 对key做转换,转换后为null的跳过
|
||||
if (null == sFieldName) {
|
||||
return;
|
||||
|
@ -17,6 +17,7 @@ import org.dromara.hutool.core.bean.PropDesc;
|
||||
import org.dromara.hutool.core.lang.Assert;
|
||||
import org.dromara.hutool.core.lang.mutable.MutableEntry;
|
||||
import org.dromara.hutool.core.reflect.TypeUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
@ -72,11 +73,11 @@ public class BeanToMapCopier extends AbsCopier<Object, Map> {
|
||||
}
|
||||
|
||||
// 编辑键值对
|
||||
final MutableEntry<String, Object> entry = copyOptions.editField(sFieldName, sValue);
|
||||
final MutableEntry<Object, Object> entry = copyOptions.editField(sFieldName, sValue);
|
||||
if(null == entry){
|
||||
return;
|
||||
}
|
||||
sFieldName = entry.getKey();
|
||||
sFieldName = StrUtil.toStringOrNull(entry.getKey());
|
||||
// 对key做转换,转换后为null的跳过
|
||||
if (null == sFieldName) {
|
||||
return;
|
||||
|
@ -67,7 +67,7 @@ public class CopyOptions implements Serializable {
|
||||
/**
|
||||
* 字段属性名和属性值编辑器,用于自定义属性转换规则(例如驼峰转下划线等),自定义属性值转换规则(例如null转""等)
|
||||
*/
|
||||
protected UnaryOperator<MutableEntry<String, Object>> fieldEditor;
|
||||
protected UnaryOperator<MutableEntry<Object, Object>> fieldEditor;
|
||||
|
||||
/**
|
||||
* 是否支持transient关键字修饰和@Transient注解,如果支持,被修饰的字段或方法对应的字段将被忽略。
|
||||
@ -264,10 +264,11 @@ public class CopyOptions implements Serializable {
|
||||
* @param fieldMapping 拷贝属性的字段映射,用于不同的属性之前拷贝做对应表用
|
||||
* @return CopyOptions
|
||||
*/
|
||||
public CopyOptions setFieldMapping(final Map<String, String> fieldMapping) {
|
||||
public CopyOptions setFieldMapping(final Map<?, ?> fieldMapping) {
|
||||
return setFieldEditor(entry -> {
|
||||
final String key = entry.getKey();
|
||||
entry.setKey(fieldMapping.getOrDefault(key, key));
|
||||
final Object key = entry.getKey();
|
||||
final Object keyMapped = fieldMapping.get(key);
|
||||
entry.setKey(null == keyMapped ? key : keyMapped);
|
||||
return entry;
|
||||
});
|
||||
}
|
||||
@ -282,7 +283,7 @@ public class CopyOptions implements Serializable {
|
||||
* @return CopyOptions
|
||||
* @since 5.4.2
|
||||
*/
|
||||
public CopyOptions setFieldEditor(final UnaryOperator<MutableEntry<String, Object>> editor) {
|
||||
public CopyOptions setFieldEditor(final UnaryOperator<MutableEntry<Object, Object>> editor) {
|
||||
this.fieldEditor = editor;
|
||||
return this;
|
||||
}
|
||||
@ -290,13 +291,13 @@ public class CopyOptions implements Serializable {
|
||||
/**
|
||||
* 编辑字段值
|
||||
*
|
||||
* @param fieldName 字段名
|
||||
* @param fieldValue 字段值
|
||||
* @param key 字段名
|
||||
* @param value 字段值
|
||||
* @return 编辑后的字段值
|
||||
* @since 5.7.15
|
||||
*/
|
||||
protected MutableEntry<String, Object> editField(final String fieldName, final Object fieldValue) {
|
||||
final MutableEntry<String, Object> entry = new MutableEntry<>(fieldName, fieldValue);
|
||||
protected MutableEntry<Object, Object> editField(final Object key, final Object value) {
|
||||
final MutableEntry<Object, Object> entry = new MutableEntry<>(key, value);
|
||||
return (null != this.fieldEditor) ?
|
||||
this.fieldEditor.apply(entry) : entry;
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ import org.dromara.hutool.core.lang.mutable.MutableEntry;
|
||||
import org.dromara.hutool.core.map.CaseInsensitiveMap;
|
||||
import org.dromara.hutool.core.map.MapWrapper;
|
||||
import org.dromara.hutool.core.reflect.TypeUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
@ -76,11 +75,11 @@ public class MapToBeanCopier<T> extends AbsCopier<Map<?, ?>, T> {
|
||||
}
|
||||
|
||||
// 编辑键值对
|
||||
final MutableEntry<String, Object> entry = copyOptions.editField(sKey.toString(), sValue);
|
||||
final MutableEntry<Object, Object> entry = copyOptions.editField(sKey, sValue);
|
||||
if(null == entry){
|
||||
return;
|
||||
}
|
||||
final String sFieldName = entry.getKey();
|
||||
final Object sFieldName = entry.getKey();
|
||||
// 对key做转换,转换后为null的跳过
|
||||
if (null == sFieldName) {
|
||||
return;
|
||||
@ -88,7 +87,7 @@ public class MapToBeanCopier<T> extends AbsCopier<Map<?, ?>, T> {
|
||||
|
||||
// 检查目标字段可写性
|
||||
// 目标字段检查放在键值对编辑之后,因为键可能被编辑修改
|
||||
final PropDesc tDesc = this.copyOptions.findPropDesc(targetPropDescMap, sFieldName);
|
||||
final PropDesc tDesc = this.copyOptions.findPropDesc(targetPropDescMap, sFieldName.toString());
|
||||
if (null == tDesc || !tDesc.isWritable(this.copyOptions.transientSupport)) {
|
||||
// 字段不可写,跳过之
|
||||
return;
|
||||
|
@ -52,7 +52,7 @@ public class MapToMapCopier extends AbsCopier<Map, Map> {
|
||||
}
|
||||
|
||||
// 编辑键值对
|
||||
final MutableEntry<String, Object> entry = copyOptions.editField(sKey.toString(), sValue);
|
||||
final MutableEntry<Object, Object> entry = copyOptions.editField(sKey, sValue);
|
||||
if(null == entry){
|
||||
return;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import org.dromara.hutool.core.bean.PropDesc;
|
||||
import org.dromara.hutool.core.lang.Assert;
|
||||
import org.dromara.hutool.core.lang.mutable.MutableEntry;
|
||||
import org.dromara.hutool.core.reflect.TypeUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
@ -72,11 +73,11 @@ public class ValueProviderToBeanCopier<T> extends AbsCopier<ValueProvider<String
|
||||
// 获取目标字段真实类型
|
||||
final Type fieldType = TypeUtil.getActualType(this.targetType ,tDesc.getFieldType());
|
||||
// 编辑键值对
|
||||
final MutableEntry<String, Object> entry = copyOptions.editField(tFieldName, null);
|
||||
final MutableEntry<Object, Object> entry = copyOptions.editField(tFieldName, null);
|
||||
if(null == entry){
|
||||
return;
|
||||
}
|
||||
tFieldName = entry.getKey();
|
||||
tFieldName = StrUtil.toStringOrNull(entry.getKey());
|
||||
// 对key做转换,转换后为null的跳过
|
||||
if (null == tFieldName) {
|
||||
return;
|
||||
|
@ -374,7 +374,7 @@ public class WordTree extends HashMap<Character, WordTree> {
|
||||
private Iterable<String> innerFlatten(final Entry<Character, WordTree> entry) {
|
||||
final List<String> list = EasyStream.of(entry.getValue().entrySet()).flat(this::innerFlatten).map(v -> entry.getKey() + v).toList();
|
||||
if (list.isEmpty()) {
|
||||
return EasyStream.of(entry.getKey().toString());
|
||||
return EasyStream.of(StrUtil.toStringOrNull(entry.getKey()));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
@ -879,7 +879,7 @@ public class BeanUtilTest {
|
||||
//setIgnoreNullValue(true).
|
||||
//setIgnoreCase(false).
|
||||
setFieldEditor(entry->{
|
||||
entry.setKey(StrUtil.toCamelCase(entry.getKey()));
|
||||
entry.setKey(StrUtil.toCamelCase(entry.getKey().toString()));
|
||||
return entry;
|
||||
});
|
||||
|
||||
|
@ -46,7 +46,7 @@ public class Issue1687Test {
|
||||
|
||||
// 补救别名错位
|
||||
final CopyOptions copyOptions = CopyOptions.of().setFieldMapping(
|
||||
MapUtil.builder("depart", "depId").build()
|
||||
MapUtil.builder((Object)"depart", (Object)"depId").build()
|
||||
);
|
||||
final SysUser sysUser = BeanUtil.toBean(sysUserFb, SysUser.class, copyOptions);
|
||||
|
||||
|
@ -35,7 +35,7 @@ public class Issue2202Test {
|
||||
headerMap.put("wechatpay-signature", "signature");
|
||||
final ResponseSignVerifyParams case1 = BeanUtil.toBean(headerMap, ResponseSignVerifyParams.class,
|
||||
CopyOptions.of().setFieldEditor(entry -> {
|
||||
entry.setKey(NamingCase.toCamelCase(entry.getKey(), '-'));
|
||||
entry.setKey(NamingCase.toCamelCase(entry.getKey().toString(), '-'));
|
||||
return entry;
|
||||
}));
|
||||
|
||||
|
@ -14,7 +14,7 @@ public class Issue3497Test {
|
||||
public void setFieldEditorTest() {
|
||||
final Map<String, String> aB = MapUtil.builder("a_b", "1").build();
|
||||
final Map<?, ?> bean = BeanUtil.toBean(aB, Map.class, CopyOptions.of().setFieldEditor((entry)->{
|
||||
entry.setKey(StrUtil.toCamelCase(entry.getKey()));
|
||||
entry.setKey(StrUtil.toCamelCase(entry.getKey().toString()));
|
||||
return entry;
|
||||
}));
|
||||
Assertions.assertEquals(bean.toString(), "{aB=1}");
|
||||
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2024. looly(loolly@aliyun.com)
|
||||
* Hutool is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* https://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.core.bean;
|
||||
|
||||
import lombok.Data;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
public class Issue3645Test {
|
||||
@Test
|
||||
public void copyPropertiesTest() {
|
||||
final User p = new User();
|
||||
p.setUserId(123L);
|
||||
|
||||
final Map<Long, User> map = new HashMap<>();
|
||||
map.put(123L,p);
|
||||
|
||||
final Map<Long, User> m = new HashMap<>();
|
||||
BeanUtil.copyProperties(map, m);
|
||||
final User u = m.get(123L);
|
||||
assertNotNull(u);
|
||||
}
|
||||
|
||||
@Data
|
||||
static class User{
|
||||
private Long userId;
|
||||
}
|
||||
}
|
@ -648,7 +648,7 @@ public class SoapClient implements HeaderOperation<SoapClient> {
|
||||
Entry entry;
|
||||
for (final Object obj : ((Map) value).entrySet()) {
|
||||
entry = (Entry) obj;
|
||||
setParam(childEle, entry.getKey().toString(), entry.getValue(), prefix);
|
||||
setParam(childEle, StrUtil.toStringOrNull(entry.getKey()), entry.getValue(), prefix);
|
||||
}
|
||||
} else {
|
||||
// 单个值
|
||||
|
@ -208,7 +208,9 @@ public class JSONObjectMapper {
|
||||
private void mapFromBean(final Object bean, final JSONObject jsonObject) {
|
||||
final CopyOptions copyOptions = InternalJSONUtil.toCopyOptions(jsonObject.config());
|
||||
if (null != this.predicate) {
|
||||
copyOptions.setFieldEditor((entry -> this.predicate.test(entry) ? entry : null));
|
||||
copyOptions.setFieldEditor((entry -> this.predicate.test(
|
||||
MutableEntry.of(StrUtil.toStringOrNull(entry.getKey()), entry.getValue())) ?
|
||||
entry : null));
|
||||
}
|
||||
BeanUtil.beanToMap(bean, jsonObject, copyOptions);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user