mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
修复props.toBean 数组字段未赋值问题
This commit is contained in:
parent
8bd76de6fe
commit
5799e018c1
@ -23,6 +23,7 @@
|
|||||||
* 【core 】 修复CalendarUtil.isSameMonth没有判断公元前导致不一致的问题(issue#3011@Github)
|
* 【core 】 修复CalendarUtil.isSameMonth没有判断公元前导致不一致的问题(issue#3011@Github)
|
||||||
* 【core 】 修复WatchUtil createModify maxDepth传递后没有使用问题(issue#3005@Github)
|
* 【core 】 修复WatchUtil createModify maxDepth传递后没有使用问题(issue#3005@Github)
|
||||||
* 【core 】 修复NullComparator反转无效问题(pr#964@Gitee)
|
* 【core 】 修复NullComparator反转无效问题(pr#964@Gitee)
|
||||||
|
* 【setting】 修复props.toBean 数组字段未赋值问题(issue#3008@Github)
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------
|
||||||
# 5.8.15 (2023-03-09)
|
# 5.8.15 (2023-03-09)
|
||||||
|
@ -10,11 +10,7 @@ import cn.hutool.core.util.NumberUtil;
|
|||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bean路径表达式,用于获取多层嵌套Bean中的字段值或Bean对象<br>
|
* Bean路径表达式,用于获取多层嵌套Bean中的字段值或Bean对象<br>
|
||||||
@ -138,18 +134,24 @@ public class BeanPath implements Serializable {
|
|||||||
*
|
*
|
||||||
* @param bean Bean、Map或List
|
* @param bean Bean、Map或List
|
||||||
* @param patternParts 表达式块列表
|
* @param patternParts 表达式块列表
|
||||||
|
* @param nextNumberPart 下一个值是否
|
||||||
* @param value 值
|
* @param value 值
|
||||||
* @return 值
|
|
||||||
*/
|
*/
|
||||||
private void set(Object bean, List<String> patternParts, boolean nextNumberPart, Object value) {
|
private void set(Object bean, List<String> patternParts, boolean nextNumberPart, Object value) {
|
||||||
Object subBean = this.get(patternParts, bean, true);
|
Object subBean = this.get(patternParts, bean, true);
|
||||||
if (null == subBean) {
|
if (null == subBean) {
|
||||||
|
// 当前节点是空,则先创建父节点
|
||||||
final List<String> parentParts = getParentParts(patternParts);
|
final List<String> parentParts = getParentParts(patternParts);
|
||||||
this.set(bean, parentParts, lastIsNumber(parentParts), nextNumberPart ? new ArrayList<>() : new HashMap<>());
|
this.set(bean, parentParts, lastIsNumber(parentParts), nextNumberPart ? new ArrayList<>() : new HashMap<>());
|
||||||
//set中有可能做过转换,因此此处重新获取bean
|
//set中有可能做过转换,因此此处重新获取bean
|
||||||
subBean = this.get(patternParts, bean, true);
|
subBean = this.get(patternParts, bean, true);
|
||||||
}
|
}
|
||||||
BeanUtil.setFieldValue(subBean, patternParts.get(patternParts.size() - 1), value);
|
|
||||||
|
final Object newSubBean = BeanUtil.setFieldValue(subBean, patternParts.get(patternParts.size() - 1), value);
|
||||||
|
if(newSubBean != subBean){
|
||||||
|
// 对象变更,重新加入
|
||||||
|
this.set(bean, getParentParts(patternParts), nextNumberPart, newSubBean);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,29 +9,12 @@ import cn.hutool.core.convert.Convert;
|
|||||||
import cn.hutool.core.lang.Editor;
|
import cn.hutool.core.lang.Editor;
|
||||||
import cn.hutool.core.map.CaseInsensitiveMap;
|
import cn.hutool.core.map.CaseInsensitiveMap;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.*;
|
||||||
import cn.hutool.core.util.ClassUtil;
|
|
||||||
import cn.hutool.core.util.ModifierUtil;
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
|
||||||
import cn.hutool.core.util.ReflectUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
|
|
||||||
import java.beans.BeanInfo;
|
import java.beans.*;
|
||||||
import java.beans.IntrospectionException;
|
|
||||||
import java.beans.Introspector;
|
|
||||||
import java.beans.PropertyDescriptor;
|
|
||||||
import java.beans.PropertyEditor;
|
|
||||||
import java.beans.PropertyEditorManager;
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -309,24 +292,32 @@ public class BeanUtil {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置字段值,通过反射设置字段值,并不调用setXXX方法<br>
|
* 设置字段值,通过反射设置字段值,并不调用setXXX方法<br>
|
||||||
* 对象同样支持Map类型,fieldNameOrIndex即为key
|
* 对象同样支持Map类型,fieldNameOrIndex即为key,支持:
|
||||||
|
* <ul>
|
||||||
|
* <li>Map</li>
|
||||||
|
* <li>List</li>
|
||||||
|
* <li>Bean</li>
|
||||||
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param bean Bean
|
* @param bean Bean
|
||||||
* @param fieldNameOrIndex 字段名或序号,序号支持负数
|
* @param fieldNameOrIndex 字段名或序号,序号支持负数
|
||||||
* @param value 值
|
* @param value 值
|
||||||
|
* @return bean,当为数组时,返回一个新的数组
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
public static void setFieldValue(Object bean, String fieldNameOrIndex, Object value) {
|
public static Object setFieldValue(Object bean, String fieldNameOrIndex, Object value) {
|
||||||
if (bean instanceof Map) {
|
if (bean instanceof Map) {
|
||||||
((Map) bean).put(fieldNameOrIndex, value);
|
((Map) bean).put(fieldNameOrIndex, value);
|
||||||
} else if (bean instanceof List) {
|
} else if (bean instanceof List) {
|
||||||
ListUtil.setOrPadding((List) bean, Convert.toInt(fieldNameOrIndex), value);
|
ListUtil.setOrPadding((List) bean, Convert.toInt(fieldNameOrIndex), value);
|
||||||
} else if (ArrayUtil.isArray(bean)) {
|
} else if (ArrayUtil.isArray(bean)) {
|
||||||
ArrayUtil.setOrAppend(bean, Convert.toInt(fieldNameOrIndex), value);
|
// issue#3008,追加产生新数组,此处返回新数组
|
||||||
|
return ArrayUtil.setOrAppend(bean, Convert.toInt(fieldNameOrIndex), value);
|
||||||
} else {
|
} else {
|
||||||
// 普通Bean对象
|
// 普通Bean对象
|
||||||
ReflectUtil.setFieldValue(bean, fieldNameOrIndex, value);
|
ReflectUtil.setFieldValue(bean, fieldNameOrIndex, value);
|
||||||
}
|
}
|
||||||
|
return bean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -611,6 +602,7 @@ public class BeanUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------- beanToMap
|
// --------------------------------------------------------------------------------------------- beanToMap
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将bean的部分属性转换成map<br>
|
* 将bean的部分属性转换成map<br>
|
||||||
* 可选拷贝哪些属性值,默认是不忽略值为{@code null}的值的。
|
* 可选拷贝哪些属性值,默认是不忽略值为{@code null}的值的。
|
||||||
@ -984,8 +976,8 @@ public class BeanUtil {
|
|||||||
* @param target 待检测对象2
|
* @param target 待检测对象2
|
||||||
* @param ignoreProperties 不需要检测的字段
|
* @param ignoreProperties 不需要检测的字段
|
||||||
* @return 判断结果,如果为true则证明所有字段的值都相同
|
* @return 判断结果,如果为true则证明所有字段的值都相同
|
||||||
* @since 5.8.4
|
|
||||||
* @author Takak11
|
* @author Takak11
|
||||||
|
* @since 5.8.4
|
||||||
*/
|
*/
|
||||||
public static boolean isCommonFieldsEqual(Object source, Object target, String... ignoreProperties) {
|
public static boolean isCommonFieldsEqual(Object source, Object target, String... ignoreProperties) {
|
||||||
|
|
||||||
|
@ -360,7 +360,8 @@ public class ArrayUtil extends PrimitiveArrayUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将元素值设置为数组的某个位置,当给定的index大于数组长度,则追加
|
* 将元素值设置为数组的某个位置,当给定的index大于数组长度,则追加<br>
|
||||||
|
* 替换时返回原数组,追加时返回新数组
|
||||||
*
|
*
|
||||||
* @param array 已有数组
|
* @param array 已有数组
|
||||||
* @param index 位置,大于长度追加,否则替换
|
* @param index 位置,大于长度追加,否则替换
|
||||||
|
@ -2,6 +2,8 @@ package cn.hutool.core.bean;
|
|||||||
|
|
||||||
import cn.hutool.core.lang.test.bean.ExamInfoDict;
|
import cn.hutool.core.lang.test.bean.ExamInfoDict;
|
||||||
import cn.hutool.core.lang.test.bean.UserInfoDict;
|
import cn.hutool.core.lang.test.bean.UserInfoDict;
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import lombok.Data;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -124,4 +126,20 @@ public class BeanPathTest {
|
|||||||
beanPath.set(map, "张三");
|
beanPath.set(map, "张三");
|
||||||
Assert.assertEquals("{list=[[null, {name=张三}]]}", map.toString());
|
Assert.assertEquals("{list=[[null, {name=张三}]]}", map.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void appendArrayTest(){
|
||||||
|
// issue#3008@Github
|
||||||
|
final MyUser myUser = new MyUser();
|
||||||
|
BeanPath.create("hobby[0]").set(myUser, "LOL");
|
||||||
|
BeanPath.create("hobby[1]").set(myUser, "KFC");
|
||||||
|
BeanPath.create("hobby[2]").set(myUser, "COFFE");
|
||||||
|
|
||||||
|
Assert.assertEquals("[LOL, KFC, COFFE]", ArrayUtil.toString(myUser.getHobby()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
static class MyUser {
|
||||||
|
private String[] hobby;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -585,7 +585,7 @@ public final class Props extends Properties implements BasicTypeGetter<String>,
|
|||||||
BeanUtil.setProperty(bean, StrUtil.subSuf(key, prefix.length()), entry.getValue());
|
BeanUtil.setProperty(bean, StrUtil.subSuf(key, prefix.length()), entry.getValue());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// 忽略注入失败的字段(这些字段可能用于其它配置)
|
// 忽略注入失败的字段(这些字段可能用于其它配置)
|
||||||
StaticLog.debug("Ignore property: [{}]", key);
|
StaticLog.debug("Ignore property: [{}],because of: {}", key, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
package cn.hutool.setting;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import cn.hutool.setting.dialect.Props;
|
||||||
|
import cn.hutool.setting.dialect.PropsUtil;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class Issue3008Test {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数组字段追加后生成新的数组,造成赋值丢失<br>
|
||||||
|
* 修复见:BeanUtil.setFieldValue
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void toBeanTest() {
|
||||||
|
final Props props = PropsUtil.get("issue3008");
|
||||||
|
final MyUser user = props.toBean(MyUser.class, "person");
|
||||||
|
Assert.assertEquals("[LOL, KFC, COFFE]", ArrayUtil.toString(user.getHobby()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
static class MyUser {
|
||||||
|
private String[] hobby;
|
||||||
|
}
|
||||||
|
}
|
@ -31,11 +31,11 @@ public class PropsTest {
|
|||||||
@Test
|
@Test
|
||||||
public void propTest() {
|
public void propTest() {
|
||||||
//noinspection MismatchedQueryAndUpdateOfCollection
|
//noinspection MismatchedQueryAndUpdateOfCollection
|
||||||
Props props = new Props("test.properties");
|
final Props props = new Props("test.properties");
|
||||||
String user = props.getProperty("user");
|
final String user = props.getProperty("user");
|
||||||
Assert.assertEquals(user, "root");
|
Assert.assertEquals(user, "root");
|
||||||
|
|
||||||
String driver = props.getStr("driver");
|
final String driver = props.getStr("driver");
|
||||||
Assert.assertEquals(driver, "com.mysql.jdbc.Driver");
|
Assert.assertEquals(driver, "com.mysql.jdbc.Driver");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,19 +43,19 @@ public class PropsTest {
|
|||||||
@Ignore
|
@Ignore
|
||||||
public void propTestForAbsPAth() {
|
public void propTestForAbsPAth() {
|
||||||
//noinspection MismatchedQueryAndUpdateOfCollection
|
//noinspection MismatchedQueryAndUpdateOfCollection
|
||||||
Props props = new Props("d:/test.properties");
|
final Props props = new Props("d:/test.properties");
|
||||||
String user = props.getProperty("user");
|
final String user = props.getProperty("user");
|
||||||
Assert.assertEquals(user, "root");
|
Assert.assertEquals(user, "root");
|
||||||
|
|
||||||
String driver = props.getStr("driver");
|
final String driver = props.getStr("driver");
|
||||||
Assert.assertEquals(driver, "com.mysql.jdbc.Driver");
|
Assert.assertEquals(driver, "com.mysql.jdbc.Driver");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void toBeanTest() {
|
public void toBeanTest() {
|
||||||
Props props = Props.getProp("to_bean_test.properties");
|
final Props props = Props.getProp("to_bean_test.properties");
|
||||||
|
|
||||||
ConfigProperties cfg = props.toBean(ConfigProperties.class, "mail");
|
final ConfigProperties cfg = props.toBean(ConfigProperties.class, "mail");
|
||||||
Assert.assertEquals("mailer@mail.com", cfg.getHost());
|
Assert.assertEquals("mailer@mail.com", cfg.getHost());
|
||||||
Assert.assertEquals(9000, cfg.getPort());
|
Assert.assertEquals(9000, cfg.getPort());
|
||||||
Assert.assertEquals("mailer@mail.com", cfg.getFrom());
|
Assert.assertEquals("mailer@mail.com", cfg.getFrom());
|
||||||
@ -73,14 +73,14 @@ public class PropsTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void toBeanWithNullPrefixTest(){
|
public void toBeanWithNullPrefixTest(){
|
||||||
Props configProp = new Props();
|
final Props configProp = new Props();
|
||||||
|
|
||||||
configProp.setProperty("createTime", Objects.requireNonNull(DateUtil.parse("2020-01-01")));
|
configProp.setProperty("createTime", Objects.requireNonNull(DateUtil.parse("2020-01-01")));
|
||||||
configProp.setProperty("isInit", true);
|
configProp.setProperty("isInit", true);
|
||||||
configProp.setProperty("stairPlan", 1);
|
configProp.setProperty("stairPlan", 1);
|
||||||
configProp.setProperty("stageNum", 2);
|
configProp.setProperty("stageNum", 2);
|
||||||
configProp.setProperty("version", 3);
|
configProp.setProperty("version", 3);
|
||||||
SystemConfig systemConfig = configProp.toBean(SystemConfig.class);
|
final SystemConfig systemConfig = configProp.toBean(SystemConfig.class);
|
||||||
|
|
||||||
Assert.assertEquals(DateUtil.parse("2020-01-01"), systemConfig.getCreateTime());
|
Assert.assertEquals(DateUtil.parse("2020-01-01"), systemConfig.getCreateTime());
|
||||||
Assert.assertEquals(true, systemConfig.getIsInit());
|
Assert.assertEquals(true, systemConfig.getIsInit());
|
||||||
|
3
hutool-setting/src/test/resources/issue3008.properties
Normal file
3
hutool-setting/src/test/resources/issue3008.properties
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
person.hobby[0]=LOL
|
||||||
|
person.hobby[1]=KFC
|
||||||
|
person.hobby[2]=COFFE
|
Loading…
x
Reference in New Issue
Block a user