修复CharSequenceUtil.move方法在局部循环位移中输出不符合预期问题(issue#IDD181@Gitee)

This commit is contained in:
Looly
2025-12-15 23:08:42 +08:00
4 changed files with 89 additions and 0 deletions

View File

@@ -5,6 +5,8 @@
### 🐣新特性
* 【core 】 `ColorUtil`颜色名称DARKGOLD、LIGHTGOLD新增蛇形命名匹配pr#1400@Github
* 【core 】 添加`BeanPath`方法中对“*”的处理逻辑pr#1412@Gitee
### 🐞Bug修复
* 【core 】 修复`Calculator.conversion`方法计算包含科学计数法表达式的值时逻辑有误结果不符合预期pr#4172@Github
* 【core 】 修复`NumberUtil.getBinaryStr`方法计算Double等丢失小数问题pr#1411@Gitee

View File

@@ -192,6 +192,17 @@ public class BeanPath implements Serializable {
String patternPart;
for (int i = 0; i < length; i++) {
patternPart = patternParts.get(i);
// 支持通配符 * 语法,用于获取集合或数组中所有元素的指定字段
if ("*".equals(patternPart)) {
// 如果当前对象是集合或数组,且后面还有路径部分,则展开处理
if (i < length - 1 && (subBean instanceof Collection || ArrayUtil.isArray(subBean))) {
return getByWildcard(subBean, patternParts, i + 1, length);
}
// 如果 * 是最后一个部分,直接返回当前集合/数组
return subBean;
}
subBean = getFieldValue(subBean, patternPart);
if (null == subBean) {
// 支持表达式的第一个对象为Bean本身若用户定义表达式$开头,则不做此操作)
@@ -206,6 +217,49 @@ public class BeanPath implements Serializable {
return subBean;
}
/**
* 处理通配符 * 的情况,对集合或数组中的每个元素应用剩余路径
*
* @param collectionOrArray 集合或数组对象
* @param patternParts 完整的表达式分段列表
* @param startIndex 剩余路径的起始索引
* @param endIndex 路径的结束索引
* @return 结果列表
*/
private Object getByWildcard(final Object collectionOrArray, final List<String> patternParts,
final int startIndex, final int endIndex) {
final List<Object> results = new ArrayList<>();
// 获取剩余的路径部分
final List<String> remainingParts = patternParts.subList(startIndex, endIndex);
if (collectionOrArray instanceof Collection) {
// 处理集合
for (Object item : (Collection<?>) collectionOrArray) {
if (item != null) {
final Object value = get(remainingParts, item, false);
if (value != null) {
results.add(value);
}
}
}
} else if (ArrayUtil.isArray(collectionOrArray)) {
// 处理数组
final int arrayLength = ArrayUtil.length(collectionOrArray);
for (int i = 0; i < arrayLength; i++) {
final Object item = ArrayUtil.get(collectionOrArray, i);
if (item != null) {
final Object value = get(remainingParts, item, false);
if (value != null) {
results.add(value);
}
}
}
}
return results.isEmpty() ? null : results;
}
@SuppressWarnings("unchecked")
private static Object getFieldValue(final Object bean, final String expression) {
if (StrUtil.isBlank(expression)) {

View File

@@ -139,6 +139,16 @@ public class BeanPathTest {
assertEquals("[LOL, KFC, COFFE]", ArrayUtil.toString(myUser.getHobby()));
}
@Test
public void wildcardTest() {
// 测试通配符 * 语法
final BeanPath pattern = BeanPath.create("userInfo.examInfoDict[*].id");
final Object result = pattern.get(tempMap);
// 应该返回一个包含所有 examInfoDict 元素的 id 的列表
assertEquals("[1, 2, 3]", result.toString());
}
@Data
static class MyUser {
private String[] hobby;

View File

@@ -50,4 +50,27 @@ public class JSONPathTest {
assertNotNull(accountIds);
assertArrayEquals(new Long[]{1L, 2L, 3L}, accountIds.toArray());
}
@Test
public void getByPathWithWildcardTest() {
// 测试通配符 [*] 语法
JSONObject root = new JSONObject()
.put("actionMessage", new JSONObject()
.put("alertResults", new JSONArray())
.put("decodeFeas", new JSONArray()
.put(new JSONObject()
.put("body", new JSONObject()
.put("lats", new JSONArray()
.put(new JSONObject().put("begin", 4260).put("text", "呵呵"))
.put(new JSONObject().put("begin", 4260).put("text", "你好 "))
)
)
)
)
);
Object byPath = JSONUtil.getByPath(root, "$.actionMessage.decodeFeas[0].body.lats[*].text");
assertNotNull(byPath);
assertEquals("[呵呵, 你好 ]", byPath.toString());
}
}