This commit is contained in:
Looly 2022-06-20 21:00:56 +08:00
parent 270bec0f37
commit 9dbb4cf85c
6 changed files with 161 additions and 58 deletions

View File

@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.math.NumberUtil;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharUtil;
@ -22,7 +23,7 @@ import java.util.Map;
* <li>.表达式可以获取Bean对象中的属性字段值或者Map中key对应的值</li>
* <li>[]表达式可以获取集合等对象中对应index的值</li>
* </ol>
*
* <p>
* 表达式栗子
*
* <pre>
@ -39,7 +40,9 @@ import java.util.Map;
public class BeanPath implements Serializable {
private static final long serialVersionUID = 1L;
/** 表达式边界符号数组 */
/**
* 表达式边界符号数组
*/
private static final char[] EXP_CHARS = {CharUtil.DOT, CharUtil.BRACKET_START, CharUtil.BRACKET_END};
private boolean isStartWith = false;
@ -53,7 +56,7 @@ public class BeanPath implements Serializable{
* <li>.表达式可以获取Bean对象中的属性字段值或者Map中key对应的值</li>
* <li>[]表达式可以获取集合等对象中对应index的值</li>
* </ol>
*
* <p>
* 表达式栗子
*
* <pre>
@ -113,7 +116,7 @@ public class BeanPath implements Serializable{
* @param value
*/
public void set(final Object bean, final Object value) {
set(bean, this.patternParts, value);
set(bean, this.patternParts, lastIsNumber(this.patternParts), value);
}
@Override
@ -122,6 +125,7 @@ public class BeanPath implements Serializable{
}
//region Private Methods
/**
* 设置表达式指定位置或filed对应的值<br>
* 若表达式指向一个List则设置其坐标对应位置的值若指向Map则put对应key的值Bean则设置字段的值<br>
@ -136,16 +140,37 @@ public class BeanPath implements Serializable{
* @param patternParts 表达式块列表
* @param value
*/
private void set(final Object bean, final List<String> patternParts, final Object value) {
Object subBean = get(patternParts, bean, true);
private void set(final Object bean, final List<String> patternParts, final boolean nextNumberPart, final Object value) {
Object subBean = this.get(patternParts, bean, true);
if (null == subBean) {
set(bean, patternParts.subList(0, patternParts.size() - 1), new HashMap<>());
final List<String> parentParts = getParentParts(patternParts);
this.set(bean, parentParts, lastIsNumber(parentParts), nextNumberPart ? new ArrayList<>() : new HashMap<>());
//set中有可能做过转换因此此处重新获取bean
subBean = get(patternParts, bean, true);
subBean = this.get(patternParts, bean, true);
}
BeanUtil.setFieldValue(subBean, patternParts.get(patternParts.size() - 1), value);
}
/**
* 判断path列表中末尾的标记是否为数字
*
* @param patternParts path列表
* @return 是否为数字
*/
private static boolean lastIsNumber(List<String> patternParts) {
return NumberUtil.isInteger(patternParts.get(patternParts.size() - 1));
}
/**
* 获取父级路径列表
*
* @param patternParts 路径列表
* @return 父级路径列表
*/
private static List<String> getParentParts(List<String> patternParts) {
return patternParts.subList(0, patternParts.size() - 1);
}
/**
* 获取Bean中对应表达式的值
*

View File

@ -319,7 +319,7 @@ public class BeanUtil {
if (bean instanceof Map) {
((Map) bean).put(fieldNameOrIndex, value);
} else if (bean instanceof List) {
ListUtil.setOrAppend((List) bean, Convert.toInt(fieldNameOrIndex), value);
ListUtil.setOrPadding((List) bean, Convert.toInt(fieldNameOrIndex), value);
} else if (ArrayUtil.isArray(bean)) {
ArrayUtil.setOrAppend(bean, Convert.toInt(fieldNameOrIndex), value);
} else {

View File

@ -7,6 +7,7 @@ import cn.hutool.core.collection.partition.RandomAccessAvgPartition;
import cn.hutool.core.collection.partition.RandomAccessPartition;
import cn.hutool.core.comparator.PinyinComparator;
import cn.hutool.core.comparator.PropertyComparator;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.PageUtil;
@ -396,6 +397,45 @@ public class ListUtil {
return list;
}
/**
* 在指定位置设置元素当index小于List的长度时替换指定位置的值否则追加{@code null}直到到达index后设置值
*
* @param <T> 元素类型
* @param list List列表
* @param index 位置
* @param element 新元素
* @return 原List
* @since 5.8.4
*/
public static <T> List<T> setOrPadding(final List<T> list, final int index, final T element) {
return setOrPadding(list, index, element, null);
}
/**
* 在指定位置设置元素当index小于List的长度时替换指定位置的值否则追加{@code paddingElement}直到到达index后设置值
*
* @param <T> 元素类型
* @param list List列表
* @param index 位置
* @param element 新元素
* @param paddingElement 填充的值
* @return 原List
* @since 58.4
*/
public static <T> List<T> setOrPadding(final List<T> list, final int index, final T element, final T paddingElement) {
Assert.notNull(list, "List must be not null !");
final int size = list.size();
if (index < size) {
list.set(index, element);
} else {
for (int i = size; i < index; i++) {
list.add(paddingElement);
}
list.add(element);
}
return list;
}
/**
* 截取集合的部分
*

View File

@ -20,7 +20,7 @@ public class LunarInfo {
public static final long BASE_DAY = LocalDate.of(BASE_YEAR, 1, 31).toEpochDay();
/**
* 此表来自https://github.com/jjonline/calendar.js/blob/master/calendar.js
* 此表来自<a href="https://github.com/jjonline/calendar.js/blob/master/calendar.js">https://github.com/jjonline/calendar.js/blob/master/calendar.js</a>
* 农历表示
* 1. 表示当年有无闰年有的话为闰月的月份没有的话为0
* 2-4.为除了闰月外的正常月份是大月还是小月1为30天0为29天
@ -61,9 +61,10 @@ public class LunarInfo {
public static int yearDays(final int y) {
int i, sum = 348;
for (i = 0x8000; i > 0x8; i >>= 1) {
if ((getCode(y) & i) != 0)
if ((getCode(y) & i) != 0) {
sum += 1;
}
}
return (sum + leapDays(y));
}

View File

@ -110,7 +110,7 @@ public class BeanPathTest {
@Test
public void getKeyWithDotTest () {
Map<String, Object> dataMap = new HashMap<>(16);
final Map<String, Object> dataMap = new HashMap<>(16);
dataMap.put("aa", "value0");
dataMap.put("aa.bb.cc", "value111111");// key 是类名 格式 ' . '
@ -125,4 +125,23 @@ public class BeanPathTest {
Assert.assertEquals("ee", of.getPatternParts().get(1));
Assert.assertEquals("ff.", of.getPatternParts().get(2));
}
@Test
public void issue2362Test() {
final Map<String, Object> map = new HashMap<>();
BeanPath beanPath = BeanPath.of("list[0].name");
beanPath.set(map, "张三");
Assert.assertEquals("{list=[{name=张三}]}", map.toString());
map.clear();
beanPath = BeanPath.of("list[1].name");
beanPath.set(map, "张三");
Assert.assertEquals("{list=[null, {name=张三}]}", map.toString());
map.clear();
beanPath = BeanPath.of("list[0].1.name");
beanPath.set(map, "张三");
Assert.assertEquals("{list=[[null, {name=张三}]]}", map.toString());
}
}

View File

@ -248,4 +248,22 @@ public class ListUtilTest {
Assert.assertEquals("2", list1.get(1));
Assert.assertEquals("3", list1.get(2));
}
@Test
public void setOrPaddingNullTest() {
final List<String> list = new ArrayList<>();
list.add("1");
// 替换原值
ListUtil.setOrPadding(list, 0, "a");
Assert.assertEquals("[a]", list.toString());
//append值
ListUtil.setOrPadding(list, 1, "a");
Assert.assertEquals("[a, a]", list.toString());
// padding null 后加入值
ListUtil.setOrPadding(list, 3, "a");
Assert.assertEquals(4, list.size());
}
}