mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
add BeanPath
This commit is contained in:
parent
b9274f5d6e
commit
ed1c3e48af
@ -1,317 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2023 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 org.dromara.hutool.core.array.ArrayUtil;
|
|
||||||
import org.dromara.hutool.core.collection.CollUtil;
|
|
||||||
import org.dromara.hutool.core.collection.ListUtil;
|
|
||||||
import org.dromara.hutool.core.convert.Convert;
|
|
||||||
import org.dromara.hutool.core.map.MapUtil;
|
|
||||||
import org.dromara.hutool.core.math.NumberUtil;
|
|
||||||
import org.dromara.hutool.core.text.CharUtil;
|
|
||||||
import org.dromara.hutool.core.text.StrUtil;
|
|
||||||
import org.dromara.hutool.core.text.split.SplitUtil;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bean路径表达式,用于获取多层嵌套Bean中的字段值或Bean对象<br>
|
|
||||||
* 根据给定的表达式,查找Bean中对应的属性值对象。 表达式分为两种:
|
|
||||||
* <ol>
|
|
||||||
* <li>.表达式,可以获取Bean对象中的属性(字段)值或者Map中key对应的值</li>
|
|
||||||
* <li>[]表达式,可以获取集合等对象中对应index的值</li>
|
|
||||||
* </ol>
|
|
||||||
* <p>
|
|
||||||
* 表达式栗子:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* persion
|
|
||||||
* persion.name
|
|
||||||
* persons[3]
|
|
||||||
* person.friends[5].name
|
|
||||||
* ['person']['friends'][5]['name']
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @author Looly
|
|
||||||
* @since 4.0.6
|
|
||||||
*/
|
|
||||||
public class BeanPathOld 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;
|
|
||||||
protected List<String> patternParts;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析Bean路径表达式为Bean模式<br>
|
|
||||||
* Bean表达式,用于获取多层嵌套Bean中的字段值或Bean对象<br>
|
|
||||||
* 根据给定的表达式,查找Bean中对应的属性值对象。 表达式分为两种:
|
|
||||||
* <ol>
|
|
||||||
* <li>.表达式,可以获取Bean对象中的属性(字段)值或者Map中key对应的值</li>
|
|
||||||
* <li>[]表达式,可以获取集合等对象中对应index的值</li>
|
|
||||||
* </ol>
|
|
||||||
* <p>
|
|
||||||
* 表达式栗子:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* persion
|
|
||||||
* persion.name
|
|
||||||
* persons[3]
|
|
||||||
* person.friends[5].name
|
|
||||||
* ['person']['friends'][5]['name']
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param expression 表达式
|
|
||||||
* @return BeanPath
|
|
||||||
*/
|
|
||||||
public static BeanPathOld of(final String expression) {
|
|
||||||
return new BeanPathOld(expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构造
|
|
||||||
*
|
|
||||||
* @param expression 表达式
|
|
||||||
*/
|
|
||||||
public BeanPathOld(final String expression) {
|
|
||||||
init(expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取表达式解析后的分段列表
|
|
||||||
*
|
|
||||||
* @return 表达式分段列表
|
|
||||||
*/
|
|
||||||
public List<String> getPatternParts() {
|
|
||||||
return this.patternParts;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取Bean中对应表达式的值
|
|
||||||
*
|
|
||||||
* @param bean Bean对象或Map或List等
|
|
||||||
* @return 值,如果对应值不存在,则返回null
|
|
||||||
*/
|
|
||||||
public Object get(final Object bean) {
|
|
||||||
return get(this.patternParts, bean);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置表达式指定位置(或filed对应)的值<br>
|
|
||||||
* 若表达式指向一个List则设置其坐标对应位置的值,若指向Map则put对应key的值,Bean则设置字段的值<br>
|
|
||||||
* 注意:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* 1. 如果为List,如果下标不大于List长度,则替换原有值,否则追加值
|
|
||||||
* 2. 如果为数组,如果下标不大于数组长度,则替换原有值,否则追加值
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param bean Bean、Map或List
|
|
||||||
* @param value 值
|
|
||||||
*/
|
|
||||||
public void set(final Object bean, final Object value) {
|
|
||||||
Objects.requireNonNull(bean);
|
|
||||||
|
|
||||||
Object subBean = bean;
|
|
||||||
Object previousBean = null;
|
|
||||||
boolean isFirst = true;
|
|
||||||
String patternPart;
|
|
||||||
// 尝试找到倒数第二个子对象, 最终需要设置它的字段值
|
|
||||||
final int length = patternParts.size() - 1;
|
|
||||||
|
|
||||||
// 填充父字段缺失的对象
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
patternPart = patternParts.get(i);
|
|
||||||
// 保存当前操作的bean, 以便subBean不存在时, 可以用来填充缺失的子对象
|
|
||||||
previousBean = subBean;
|
|
||||||
// 获取当前对象的子对象
|
|
||||||
subBean = getFieldValue(subBean, patternPart);
|
|
||||||
if (null == subBean) {
|
|
||||||
// 支持表达式的第一个对象为Bean本身(若用户定义表达式$开头,则不做此操作)
|
|
||||||
if (isFirst && !this.isStartWith && BeanUtil.isMatchName(bean, patternPart, true)) {
|
|
||||||
subBean = bean;
|
|
||||||
isFirst = false;
|
|
||||||
} else {
|
|
||||||
// 填充缺失的子对象, 根据下一个表达式决定填充的值, 如果是整数(下标)则使用列表, 否则当做Map对象
|
|
||||||
subBean = NumberUtil.isInteger(patternParts.get(i + 1)) ? new ArrayList<>() : new HashMap<>();
|
|
||||||
BeanUtil.setFieldValue(previousBean, patternPart, subBean);
|
|
||||||
// 上面setFieldValue中有可能发生对象转换, 因此此处重新获取子对象
|
|
||||||
// 欲知详情请自行阅读FieldUtil.setFieldValue(Object, Field, Object)
|
|
||||||
subBean = BeanUtil.getFieldValue(previousBean, patternPart);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置最终的(当前)字段值
|
|
||||||
final Object newSubBean = BeanUtil.setFieldValue(subBean, patternParts.get(length), value);
|
|
||||||
if(newSubBean != subBean && null != previousBean){
|
|
||||||
// 对象变更,重新加入
|
|
||||||
BeanUtil.setFieldValue(previousBean, patternParts.get(length - 1), newSubBean);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return this.patternParts.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
//region Private Methods
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取Bean中对应表达式的值
|
|
||||||
*
|
|
||||||
* @param patternParts 表达式分段列表
|
|
||||||
* @param bean Bean对象或Map或List等
|
|
||||||
* @return 值,如果对应值不存在,则返回null
|
|
||||||
*/
|
|
||||||
private Object get(final List<String> patternParts, final Object bean) {
|
|
||||||
Object subBean = bean;
|
|
||||||
boolean isFirst = true;
|
|
||||||
for (final String patternPart : patternParts) {
|
|
||||||
subBean = getFieldValue(subBean, patternPart);
|
|
||||||
if (null == subBean) {
|
|
||||||
// 支持表达式的第一个对象为Bean本身(若用户定义表达式$开头,则不做此操作)
|
|
||||||
if (isFirst && !this.isStartWith && BeanUtil.isMatchName(bean, patternPart, true)) {
|
|
||||||
subBean = bean;
|
|
||||||
isFirst = false;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return subBean;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private static Object getFieldValue(final Object bean, final String expression) {
|
|
||||||
if (StrUtil.isBlank(expression)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StrUtil.contains(expression, CharUtil.COLON)) {
|
|
||||||
// [start:end:step] 模式
|
|
||||||
final List<String> parts = SplitUtil.splitTrim(expression, StrUtil.COLON);
|
|
||||||
final int start = Integer.parseInt(parts.get(0));
|
|
||||||
final int end = Integer.parseInt(parts.get(1));
|
|
||||||
int step = 1;
|
|
||||||
if (3 == parts.size()) {
|
|
||||||
step = Integer.parseInt(parts.get(2));
|
|
||||||
}
|
|
||||||
if (bean instanceof Collection) {
|
|
||||||
return CollUtil.sub((Collection<?>) bean, start, end, step);
|
|
||||||
} else if (ArrayUtil.isArray(bean)) {
|
|
||||||
return ArrayUtil.sub(bean, start, end, step);
|
|
||||||
}
|
|
||||||
} else if (StrUtil.contains(expression, ',')) {
|
|
||||||
// [num0,num1,num2...]模式或者['key0','key1']模式
|
|
||||||
final List<String> keys = SplitUtil.splitTrim(expression, StrUtil.COMMA);
|
|
||||||
if (bean instanceof Collection) {
|
|
||||||
return CollUtil.getAny((Collection<?>) bean, Convert.convert(int[].class, keys));
|
|
||||||
} else if (ArrayUtil.isArray(bean)) {
|
|
||||||
return ArrayUtil.getAny(bean, Convert.convert(int[].class, keys));
|
|
||||||
} else {
|
|
||||||
final String[] unWrappedKeys = new String[keys.size()];
|
|
||||||
for (int i = 0; i < unWrappedKeys.length; i++) {
|
|
||||||
unWrappedKeys[i] = StrUtil.unWrap(keys.get(i), CharUtil.SINGLE_QUOTE);
|
|
||||||
}
|
|
||||||
if (bean instanceof Map) {
|
|
||||||
// 只支持String为key的Map
|
|
||||||
return MapUtil.getAny((Map<String, ?>) bean, unWrappedKeys);
|
|
||||||
} else {
|
|
||||||
final Map<String, Object> map = BeanUtil.beanToMap(bean);
|
|
||||||
return MapUtil.getAny(map, unWrappedKeys);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 数字或普通字符串
|
|
||||||
return BeanUtil.getFieldValue(bean, expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化
|
|
||||||
*
|
|
||||||
* @param expression 表达式
|
|
||||||
*/
|
|
||||||
private void init(final String expression) {
|
|
||||||
final List<String> localPatternParts = new ArrayList<>();
|
|
||||||
final int length = expression.length();
|
|
||||||
|
|
||||||
final StringBuilder builder = new StringBuilder();
|
|
||||||
char c;
|
|
||||||
boolean isNumStart = false;// 下标标识符开始
|
|
||||||
boolean isInWrap = false; //标识是否在引号内
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
c = expression.charAt(i);
|
|
||||||
if (0 == i && '$' == c) {
|
|
||||||
// 忽略开头的$符,表示当前对象
|
|
||||||
isStartWith = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('\'' == c) {
|
|
||||||
// 结束
|
|
||||||
isInWrap = (!isInWrap);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isInWrap && ArrayUtil.contains(EXP_CHARS, c)) {
|
|
||||||
// 处理边界符号
|
|
||||||
if (CharUtil.BRACKET_END == c) {
|
|
||||||
// 中括号(数字下标)结束
|
|
||||||
if (!isNumStart) {
|
|
||||||
throw new IllegalArgumentException(StrUtil.format("Bad expression '{}':{}, we find ']' but no '[' !", expression, i));
|
|
||||||
}
|
|
||||||
isNumStart = false;
|
|
||||||
// 中括号结束加入下标
|
|
||||||
} else {
|
|
||||||
if (isNumStart) {
|
|
||||||
// 非结束中括号情况下发现起始中括号报错(中括号未关闭)
|
|
||||||
throw new IllegalArgumentException(StrUtil.format("Bad expression '{}':{}, we find '[' but no ']' !", expression, i));
|
|
||||||
} else if (CharUtil.BRACKET_START == c) {
|
|
||||||
// 数字下标开始
|
|
||||||
isNumStart = true;
|
|
||||||
}
|
|
||||||
// 每一个边界符之前的表达式是一个完整的KEY,开始处理KEY
|
|
||||||
}
|
|
||||||
if (builder.length() > 0) {
|
|
||||||
localPatternParts.add(builder.toString());
|
|
||||||
}
|
|
||||||
builder.setLength(0);
|
|
||||||
} else {
|
|
||||||
// 非边界符号,追加字符
|
|
||||||
builder.append(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 末尾边界符检查
|
|
||||||
if (isNumStart) {
|
|
||||||
throw new IllegalArgumentException(StrUtil.format("Bad expression '{}':{}, we find '[' but no ']' !", expression, length - 1));
|
|
||||||
} else {
|
|
||||||
if (builder.length() > 0) {
|
|
||||||
localPatternParts.add(builder.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 不可变List
|
|
||||||
this.patternParts = ListUtil.view(localPatternParts);
|
|
||||||
}
|
|
||||||
//endregion
|
|
||||||
}
|
|
@ -16,6 +16,7 @@ import org.dromara.hutool.core.array.ArrayUtil;
|
|||||||
import org.dromara.hutool.core.bean.copier.BeanCopier;
|
import org.dromara.hutool.core.bean.copier.BeanCopier;
|
||||||
import org.dromara.hutool.core.bean.copier.CopyOptions;
|
import org.dromara.hutool.core.bean.copier.CopyOptions;
|
||||||
import org.dromara.hutool.core.bean.copier.ValueProvider;
|
import org.dromara.hutool.core.bean.copier.ValueProvider;
|
||||||
|
import org.dromara.hutool.core.bean.path.BeanPath;
|
||||||
import org.dromara.hutool.core.collection.CollUtil;
|
import org.dromara.hutool.core.collection.CollUtil;
|
||||||
import org.dromara.hutool.core.collection.ListUtil;
|
import org.dromara.hutool.core.collection.ListUtil;
|
||||||
import org.dromara.hutool.core.collection.set.SetUtil;
|
import org.dromara.hutool.core.collection.set.SetUtil;
|
||||||
@ -355,7 +356,7 @@ public class BeanUtil {
|
|||||||
* @param bean Bean对象,支持Map、List、Collection、Array
|
* @param bean Bean对象,支持Map、List、Collection、Array
|
||||||
* @param expression 表达式,例如:person.friend[5].name
|
* @param expression 表达式,例如:person.friend[5].name
|
||||||
* @return Bean属性值,bean为{@code null}或者express为空,返回{@code null}
|
* @return Bean属性值,bean为{@code null}或者express为空,返回{@code null}
|
||||||
* @see BeanPathOld#get(Object)
|
* @see BeanPath#getValue(Object)
|
||||||
* @since 3.0.7
|
* @since 3.0.7
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@ -363,7 +364,7 @@ public class BeanUtil {
|
|||||||
if (null == bean || StrUtil.isBlank(expression)) {
|
if (null == bean || StrUtil.isBlank(expression)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (T) BeanPathOld.of(expression).get(bean);
|
return (T) BeanPath.of(expression).getValue(bean);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -372,11 +373,11 @@ public class BeanUtil {
|
|||||||
* @param bean Bean对象,支持Map、List、Collection、Array
|
* @param bean Bean对象,支持Map、List、Collection、Array
|
||||||
* @param expression 表达式,例如:person.friend[5].name
|
* @param expression 表达式,例如:person.friend[5].name
|
||||||
* @param value 属性值
|
* @param value 属性值
|
||||||
* @see BeanPathOld#get(Object)
|
* @see BeanPath#setValue(Object, Object)
|
||||||
* @since 4.0.6
|
* @since 4.0.6
|
||||||
*/
|
*/
|
||||||
public static void setProperty(final Object bean, final String expression, final Object value) {
|
public static void setProperty(final Object bean, final String expression, final Object value) {
|
||||||
BeanPathOld.of(expression).set(bean, value);
|
BeanPath.of(expression).setValue(bean, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------- mapToBean
|
// --------------------------------------------------------------------------------------------- mapToBean
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
package org.dromara.hutool.core.bean;
|
package org.dromara.hutool.core.bean;
|
||||||
|
|
||||||
|
import org.dromara.hutool.core.array.ArrayUtil;
|
||||||
import org.dromara.hutool.core.collection.CollUtil;
|
import org.dromara.hutool.core.collection.CollUtil;
|
||||||
import org.dromara.hutool.core.collection.ListUtil;
|
import org.dromara.hutool.core.collection.ListUtil;
|
||||||
import org.dromara.hutool.core.convert.Convert;
|
import org.dromara.hutool.core.convert.Convert;
|
||||||
@ -37,7 +38,7 @@ public class DynaBean implements Cloneable, Serializable {
|
|||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final Class<?> beanClass;
|
private final Class<?> beanClass;
|
||||||
private final Object bean;
|
private Object bean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建一个DynaBean
|
* 创建一个DynaBean
|
||||||
@ -101,6 +102,13 @@ public class DynaBean implements Cloneable, Serializable {
|
|||||||
// 非数字,see pr#254@Gitee
|
// 非数字,see pr#254@Gitee
|
||||||
return (T) CollUtil.map((Collection<?>) bean, (beanEle) -> DynaBean.of(beanEle).get(fieldName), false);
|
return (T) CollUtil.map((Collection<?>) bean, (beanEle) -> DynaBean.of(beanEle).get(fieldName), false);
|
||||||
}
|
}
|
||||||
|
} else if (ArrayUtil.isArray(bean)) {
|
||||||
|
try {
|
||||||
|
return ArrayUtil.get(bean, Integer.parseInt(fieldName));
|
||||||
|
} catch (final NumberFormatException e) {
|
||||||
|
// 非数字,see pr#254@Gitee
|
||||||
|
return (T) ArrayUtil.map(bean, Object.class, (beanEle) -> DynaBean.of(beanEle).get(fieldName));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
final PropDesc prop = BeanUtil.getBeanDesc(beanClass).getProp(fieldName);
|
final PropDesc prop = BeanUtil.getBeanDesc(beanClass).getProp(fieldName);
|
||||||
if (null == prop) {
|
if (null == prop) {
|
||||||
@ -148,21 +156,27 @@ public class DynaBean implements Cloneable, Serializable {
|
|||||||
*
|
*
|
||||||
* @param fieldName 字段名
|
* @param fieldName 字段名
|
||||||
* @param value 字段值
|
* @param value 字段值
|
||||||
|
* @return this;
|
||||||
* @throws BeanException 反射获取属性值或字段值导致的异常
|
* @throws BeanException 反射获取属性值或字段值导致的异常
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
public void set(final String fieldName, final Object value) throws BeanException {
|
public DynaBean set(final String fieldName, final Object value) throws BeanException {
|
||||||
if (Map.class.isAssignableFrom(beanClass)) {
|
if (Map.class.isAssignableFrom(beanClass)) {
|
||||||
((Map) bean).put(fieldName, value);
|
((Map) bean).put(fieldName, value);
|
||||||
} else if (bean instanceof List) {
|
} else if (bean instanceof List) {
|
||||||
ListUtil.setOrPadding((List) bean, Convert.toInt(fieldName), value);
|
ListUtil.setOrPadding((List) bean, Convert.toInt(fieldName), value);
|
||||||
|
} else if (ArrayUtil.isArray(bean)) {
|
||||||
|
// issue#3008,追加产生新数组,此处返回新数组
|
||||||
|
this.bean = ArrayUtil.setOrPadding(bean, Convert.toInt(fieldName), value);
|
||||||
} else {
|
} else {
|
||||||
final PropDesc prop = BeanUtil.getBeanDesc(beanClass).getProp(fieldName);
|
final PropDesc prop = BeanUtil.getBeanDesc(beanClass).getProp(fieldName);
|
||||||
if (null == prop) {
|
if (null == prop) {
|
||||||
throw new BeanException("No public field or set method for '{}'", fieldName);
|
throw new BeanException("No public field or set method for '{}'", fieldName);
|
||||||
}
|
}
|
||||||
prop.setValue(bean, value);
|
|
||||||
|
prop.setValue(bean, value, false, false);
|
||||||
}
|
}
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,7 +16,10 @@ import org.dromara.hutool.core.annotation.AnnotationUtil;
|
|||||||
import org.dromara.hutool.core.annotation.PropIgnore;
|
import org.dromara.hutool.core.annotation.PropIgnore;
|
||||||
import org.dromara.hutool.core.convert.Convert;
|
import org.dromara.hutool.core.convert.Convert;
|
||||||
import org.dromara.hutool.core.func.LambdaUtil;
|
import org.dromara.hutool.core.func.LambdaUtil;
|
||||||
import org.dromara.hutool.core.reflect.*;
|
import org.dromara.hutool.core.reflect.FieldUtil;
|
||||||
|
import org.dromara.hutool.core.reflect.ModifierUtil;
|
||||||
|
import org.dromara.hutool.core.reflect.ReflectUtil;
|
||||||
|
import org.dromara.hutool.core.reflect.TypeUtil;
|
||||||
import org.dromara.hutool.core.reflect.method.MethodUtil;
|
import org.dromara.hutool.core.reflect.method.MethodUtil;
|
||||||
|
|
||||||
import java.beans.Transient;
|
import java.beans.Transient;
|
||||||
|
@ -171,23 +171,29 @@ public class BeanPath implements Iterator<BeanPath> {
|
|||||||
*
|
*
|
||||||
* @param bean Bean对象
|
* @param bean Bean对象
|
||||||
* @param value 设置的值
|
* @param value 设置的值
|
||||||
|
* @return bean。如果在原Bean对象基础上设置值,返回原Bean,否则返回新的Bean
|
||||||
*/
|
*/
|
||||||
public void setValue(Object bean, final Object value) {
|
public Object setValue(final Object bean, final Object value) {
|
||||||
Object parentBean;
|
if (!hasNext()) {
|
||||||
BeanPath beanPath = this;
|
// 根节点,直接赋值
|
||||||
while (beanPath.hasNext()) {
|
return this.node.setValue(bean, value);
|
||||||
parentBean = bean;
|
|
||||||
bean = beanPath.node.getValue(bean);
|
|
||||||
if (null == bean) {
|
|
||||||
final BeanPath child = beanPath.next();
|
|
||||||
bean = isListNode(child.node) ? new ArrayList<>() : new HashMap<>();
|
|
||||||
beanPath.node.setValue(parentBean, bean);
|
|
||||||
// 如果自定义put方法修改了value,此处二次get避免丢失
|
|
||||||
bean = beanPath.node.getValue(parentBean);
|
|
||||||
}
|
}
|
||||||
beanPath = beanPath.next();
|
|
||||||
|
final BeanPath childBeanPath = next();
|
||||||
|
Object subBean = this.node.getValue(bean);
|
||||||
|
if (null == subBean) {
|
||||||
|
subBean = isListNode(childBeanPath.node) ? new ArrayList<>() : new HashMap<>();
|
||||||
|
this.node.setValue(bean, subBean);
|
||||||
|
// 如果自定义put方法修改了value,返回修改后的value,避免值丢失
|
||||||
|
subBean = this.node.getValue(bean);
|
||||||
}
|
}
|
||||||
beanPath.node.setValue(bean, value);
|
// 递归逐层查找子节点,赋值
|
||||||
|
final Object newSubBean = childBeanPath.setValue(subBean, value);
|
||||||
|
if(newSubBean != subBean){
|
||||||
|
//对于数组对象,set新值后,会返回新的数组,此时将新对象再加入父bean中,覆盖旧数组
|
||||||
|
this.node.setValue(bean, newSubBean);
|
||||||
|
}
|
||||||
|
return bean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -30,7 +30,8 @@ public class EmptyNode implements Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setValue(final Object bean, final Object value) {
|
public Object setValue(final Object bean, final Object value) {
|
||||||
// do nothing
|
// do nothing
|
||||||
|
return bean;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ public class ListNode implements Node{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setValue(final Object bean, final Object value) {
|
public Object setValue(final Object bean, final Object value) {
|
||||||
throw new UnsupportedOperationException("Can not set value to multi names.");
|
throw new UnsupportedOperationException("Can not set value to multi names.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,8 +55,8 @@ public class NameNode implements Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setValue(final Object bean, final Object value) {
|
public Object setValue(final Object bean, final Object value) {
|
||||||
DynaBean.of(bean).set(this.name, value);
|
return DynaBean.of(bean).set(this.name, value).getBean();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -31,6 +31,7 @@ public interface Node {
|
|||||||
*
|
*
|
||||||
* @param bean bean对象
|
* @param bean bean对象
|
||||||
* @param value 节点值
|
* @param value 节点值
|
||||||
|
* @return bean对象。如果在原Bean对象基础上设置值,返回原Bean,否则返回新的Bean
|
||||||
*/
|
*/
|
||||||
void setValue(Object bean, Object value);
|
Object setValue(Object bean, Object value);
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ public class RangeNode implements Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setValue(final Object bean, final Object value) {
|
public Object setValue(final Object bean, final Object value) {
|
||||||
throw new UnsupportedOperationException("Can not set value with step name.");
|
throw new UnsupportedOperationException("Can not set value with step name.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,26 +12,21 @@
|
|||||||
|
|
||||||
package org.dromara.hutool.core.map;
|
package org.dromara.hutool.core.map;
|
||||||
|
|
||||||
import org.dromara.hutool.core.bean.BeanPathOld;
|
|
||||||
import org.dromara.hutool.core.bean.BeanUtil;
|
import org.dromara.hutool.core.bean.BeanUtil;
|
||||||
import org.dromara.hutool.core.bean.copier.CopyOptions;
|
import org.dromara.hutool.core.bean.copier.CopyOptions;
|
||||||
|
import org.dromara.hutool.core.bean.path.BeanPath;
|
||||||
import org.dromara.hutool.core.collection.set.SetUtil;
|
import org.dromara.hutool.core.collection.set.SetUtil;
|
||||||
import org.dromara.hutool.core.convert.Convert;
|
import org.dromara.hutool.core.convert.Convert;
|
||||||
import org.dromara.hutool.core.exception.CloneException;
|
import org.dromara.hutool.core.exception.CloneException;
|
||||||
import org.dromara.hutool.core.lang.Assert;
|
|
||||||
import org.dromara.hutool.core.func.LambdaInfo;
|
import org.dromara.hutool.core.func.LambdaInfo;
|
||||||
import org.dromara.hutool.core.func.LambdaUtil;
|
import org.dromara.hutool.core.func.LambdaUtil;
|
||||||
import org.dromara.hutool.core.func.SerFunction;
|
import org.dromara.hutool.core.func.SerFunction;
|
||||||
import org.dromara.hutool.core.func.SerSupplier;
|
import org.dromara.hutool.core.func.SerSupplier;
|
||||||
|
import org.dromara.hutool.core.lang.Assert;
|
||||||
import org.dromara.hutool.core.lang.getter.TypeGetter;
|
import org.dromara.hutool.core.lang.getter.TypeGetter;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 字典对象,扩充了LinkedHashMap中的方法
|
* 字典对象,扩充了LinkedHashMap中的方法
|
||||||
@ -423,12 +418,12 @@ public class Dict extends CustomKeyMap<String, Object> implements TypeGetter<Str
|
|||||||
* @param <T> 目标类型
|
* @param <T> 目标类型
|
||||||
* @param expression 表达式
|
* @param expression 表达式
|
||||||
* @return 对象
|
* @return 对象
|
||||||
* @see BeanPathOld#get(Object)
|
* @see BeanPath#getValue(Object)
|
||||||
* @since 5.7.14
|
* @since 5.7.14
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> T getByPath(final String expression) {
|
public <T> T getByPath(final String expression) {
|
||||||
return (T) BeanPathOld.of(expression).get(this);
|
return (T) BeanPath.of(expression).getValue(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -453,7 +448,7 @@ public class Dict extends CustomKeyMap<String, Object> implements TypeGetter<Str
|
|||||||
* @param expression 表达式
|
* @param expression 表达式
|
||||||
* @param resultType 返回值类型
|
* @param resultType 返回值类型
|
||||||
* @return 对象
|
* @return 对象
|
||||||
* @see BeanPathOld#get(Object)
|
* @see BeanPath#getValue(Object)
|
||||||
* @since 5.7.14
|
* @since 5.7.14
|
||||||
*/
|
*/
|
||||||
public <T> T getByPath(final String expression, final Type resultType) {
|
public <T> T getByPath(final String expression, final Type resultType) {
|
||||||
|
@ -1,210 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2023 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 org.dromara.hutool.core.array.ArrayUtil;
|
|
||||||
import org.dromara.hutool.core.lang.test.bean.ExamInfoDict;
|
|
||||||
import org.dromara.hutool.core.lang.test.bean.UserInfoDict;
|
|
||||||
import org.dromara.hutool.core.map.Dict;
|
|
||||||
import lombok.Data;
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link BeanPathOld} 单元测试
|
|
||||||
*
|
|
||||||
* @author looly
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class BeanPathTest {
|
|
||||||
|
|
||||||
Map<String, Object> tempMap;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void init() {
|
|
||||||
// ------------------------------------------------- 考试信息列表
|
|
||||||
final ExamInfoDict examInfoDict = new ExamInfoDict();
|
|
||||||
examInfoDict.setId(1);
|
|
||||||
examInfoDict.setExamType(0);
|
|
||||||
examInfoDict.setAnswerIs(1);
|
|
||||||
|
|
||||||
final ExamInfoDict examInfoDict1 = new ExamInfoDict();
|
|
||||||
examInfoDict1.setId(2);
|
|
||||||
examInfoDict1.setExamType(0);
|
|
||||||
examInfoDict1.setAnswerIs(0);
|
|
||||||
|
|
||||||
final ExamInfoDict examInfoDict2 = new ExamInfoDict();
|
|
||||||
examInfoDict2.setId(3);
|
|
||||||
examInfoDict2.setExamType(1);
|
|
||||||
examInfoDict2.setAnswerIs(0);
|
|
||||||
|
|
||||||
final List<ExamInfoDict> examInfoDicts = new ArrayList<>();
|
|
||||||
examInfoDicts.add(examInfoDict);
|
|
||||||
examInfoDicts.add(examInfoDict1);
|
|
||||||
examInfoDicts.add(examInfoDict2);
|
|
||||||
|
|
||||||
// ------------------------------------------------- 用户信息
|
|
||||||
final UserInfoDict userInfoDict = new UserInfoDict();
|
|
||||||
userInfoDict.setId(1);
|
|
||||||
userInfoDict.setPhotoPath("yx.mm.com");
|
|
||||||
userInfoDict.setRealName("张三");
|
|
||||||
userInfoDict.setExamInfoDict(examInfoDicts);
|
|
||||||
|
|
||||||
tempMap = new HashMap<>();
|
|
||||||
tempMap.put("userInfo", userInfoDict);
|
|
||||||
tempMap.put("flag", 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void beanPathTest1() {
|
|
||||||
final BeanPathOld pattern = new BeanPathOld("userInfo.examInfoDict[0].id");
|
|
||||||
Assertions.assertEquals("userInfo", pattern.patternParts.get(0));
|
|
||||||
Assertions.assertEquals("examInfoDict", pattern.patternParts.get(1));
|
|
||||||
Assertions.assertEquals("0", pattern.patternParts.get(2));
|
|
||||||
Assertions.assertEquals("id", pattern.patternParts.get(3));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void beanPathTest2() {
|
|
||||||
final BeanPathOld pattern = new BeanPathOld("[userInfo][examInfoDict][0][id]");
|
|
||||||
Assertions.assertEquals("userInfo", pattern.patternParts.get(0));
|
|
||||||
Assertions.assertEquals("examInfoDict", pattern.patternParts.get(1));
|
|
||||||
Assertions.assertEquals("0", pattern.patternParts.get(2));
|
|
||||||
Assertions.assertEquals("id", pattern.patternParts.get(3));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void beanPathTest3() {
|
|
||||||
final BeanPathOld pattern = new BeanPathOld("['userInfo']['examInfoDict'][0]['id']");
|
|
||||||
Assertions.assertEquals("userInfo", pattern.patternParts.get(0));
|
|
||||||
Assertions.assertEquals("examInfoDict", pattern.patternParts.get(1));
|
|
||||||
Assertions.assertEquals("0", pattern.patternParts.get(2));
|
|
||||||
Assertions.assertEquals("id", pattern.patternParts.get(3));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getTest() {
|
|
||||||
final BeanPathOld pattern = BeanPathOld.of("userInfo.examInfoDict[0].id");
|
|
||||||
final Object result = pattern.get(tempMap);
|
|
||||||
Assertions.assertEquals(1, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void setTest() {
|
|
||||||
final BeanPathOld pattern = BeanPathOld.of("userInfo.examInfoDict[0].id");
|
|
||||||
pattern.set(tempMap, 2);
|
|
||||||
final Object result = pattern.get(tempMap);
|
|
||||||
Assertions.assertEquals(2, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getMapTest () {
|
|
||||||
final BeanPathOld pattern = BeanPathOld.of("userInfo[id, photoPath]");
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
final Map<String, Object> result = (Map<String, Object>)pattern.get(tempMap);
|
|
||||||
Assertions.assertEquals(1, result.get("id"));
|
|
||||||
Assertions.assertEquals("yx.mm.com", result.get("photoPath"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getKeyWithDotTest () {
|
|
||||||
final Map<String, Object> dataMap = new HashMap<>(16);
|
|
||||||
dataMap.put("aa", "value0");
|
|
||||||
dataMap.put("aa.bb.cc", "value111111");// key 是类名 格式 带 ' . '
|
|
||||||
|
|
||||||
final BeanPathOld pattern = BeanPathOld.of("'aa.bb.cc'");
|
|
||||||
Assertions.assertEquals("value111111", pattern.get(dataMap));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void compileTest(){
|
|
||||||
final BeanPathOld of = BeanPathOld.of("'abc.dd'.ee.ff'.'");
|
|
||||||
Assertions.assertEquals("abc.dd", of.getPatternParts().get(0));
|
|
||||||
Assertions.assertEquals("ee", of.getPatternParts().get(1));
|
|
||||||
Assertions.assertEquals("ff.", of.getPatternParts().get(2));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void issue2362Test() {
|
|
||||||
final Map<String, Object> map = new HashMap<>();
|
|
||||||
|
|
||||||
BeanPathOld beanPath = BeanPathOld.of("list[0].name");
|
|
||||||
beanPath.set(map, "张三");
|
|
||||||
Assertions.assertEquals("{list=[{name=张三}]}", map.toString());
|
|
||||||
|
|
||||||
map.clear();
|
|
||||||
beanPath = BeanPathOld.of("list[1].name");
|
|
||||||
beanPath.set(map, "张三");
|
|
||||||
Assertions.assertEquals("{list=[null, {name=张三}]}", map.toString());
|
|
||||||
|
|
||||||
map.clear();
|
|
||||||
beanPath = BeanPathOld.of("list[0].1.name");
|
|
||||||
beanPath.set(map, "张三");
|
|
||||||
Assertions.assertEquals("{list=[[null, {name=张三}]]}", map.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void putTest() {
|
|
||||||
final Map<String, Object> map = new HashMap<>();
|
|
||||||
|
|
||||||
final BeanPathOld beanPath = BeanPathOld.of("list[1].name");
|
|
||||||
beanPath.set(map, "张三");
|
|
||||||
Assertions.assertEquals("{list=[null, {name=张三}]}", map.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void putByPathTest() {
|
|
||||||
final Dict dict = new Dict();
|
|
||||||
BeanPathOld.of("aa.bb").set(dict, "BB");
|
|
||||||
Assertions.assertEquals("{aa={bb=BB}}", dict.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void appendArrayTest(){
|
|
||||||
// issue#3008@Github
|
|
||||||
final MyUser myUser = new MyUser();
|
|
||||||
BeanPathOld.of("hobby[0]").set(myUser, "LOL");
|
|
||||||
BeanPathOld.of("hobby[1]").set(myUser, "KFC");
|
|
||||||
BeanPathOld.of("hobby[2]").set(myUser, "COFFE");
|
|
||||||
|
|
||||||
Assertions.assertEquals("[LOL, KFC, COFFE]", ArrayUtil.toString(myUser.getHobby()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void appendArrayTest2(){
|
|
||||||
// issue#3008@Github
|
|
||||||
final MyUser2 myUser = new MyUser2();
|
|
||||||
BeanPathOld.of("myUser.hobby[0]").set(myUser, "LOL");
|
|
||||||
BeanPathOld.of("myUser.hobby[1]").set(myUser, "KFC");
|
|
||||||
BeanPathOld.of("myUser.hobby[2]").set(myUser, "COFFE");
|
|
||||||
|
|
||||||
Assertions.assertEquals("[LOL, KFC, COFFE]", ArrayUtil.toString(myUser.getMyUser().getHobby()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
|
||||||
static class MyUser {
|
|
||||||
private String[] hobby;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
|
||||||
static class MyUser2 {
|
|
||||||
private MyUser myUser;
|
|
||||||
}
|
|
||||||
}
|
|
@ -12,10 +12,16 @@
|
|||||||
|
|
||||||
package org.dromara.hutool.core.bean;
|
package org.dromara.hutool.core.bean;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
import org.dromara.hutool.core.annotation.Alias;
|
import org.dromara.hutool.core.annotation.Alias;
|
||||||
import org.dromara.hutool.core.array.ArrayUtil;
|
import org.dromara.hutool.core.array.ArrayUtil;
|
||||||
import org.dromara.hutool.core.bean.copier.CopyOptions;
|
import org.dromara.hutool.core.bean.copier.CopyOptions;
|
||||||
import org.dromara.hutool.core.bean.copier.ValueProvider;
|
import org.dromara.hutool.core.bean.copier.ValueProvider;
|
||||||
|
import org.dromara.hutool.core.bean.path.BeanPath;
|
||||||
import org.dromara.hutool.core.collection.ListUtil;
|
import org.dromara.hutool.core.collection.ListUtil;
|
||||||
import org.dromara.hutool.core.collection.set.SetUtil;
|
import org.dromara.hutool.core.collection.set.SetUtil;
|
||||||
import org.dromara.hutool.core.map.MapBuilder;
|
import org.dromara.hutool.core.map.MapBuilder;
|
||||||
@ -23,11 +29,6 @@ import org.dromara.hutool.core.map.MapUtil;
|
|||||||
import org.dromara.hutool.core.text.StrUtil;
|
import org.dromara.hutool.core.text.StrUtil;
|
||||||
import org.dromara.hutool.core.thread.ThreadUtil;
|
import org.dromara.hutool.core.thread.ThreadUtil;
|
||||||
import org.dromara.hutool.core.util.ObjUtil;
|
import org.dromara.hutool.core.util.ObjUtil;
|
||||||
import lombok.Data;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import lombok.ToString;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.Disabled;
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -767,8 +768,8 @@ public class BeanUtilTest {
|
|||||||
|
|
||||||
testPojo.setTestPojo2List(new TestPojo2[]{testPojo2, testPojo3});
|
testPojo.setTestPojo2List(new TestPojo2[]{testPojo2, testPojo3});
|
||||||
|
|
||||||
final BeanPathOld beanPath = BeanPathOld.of("testPojo2List.age");
|
final BeanPath beanPath = BeanPath.of("testPojo2List.age");
|
||||||
final Object o = beanPath.get(testPojo);
|
final Object o = beanPath.getValue(testPojo);
|
||||||
|
|
||||||
Assertions.assertEquals(Integer.valueOf(2), ArrayUtil.get(o, 0));
|
Assertions.assertEquals(Integer.valueOf(2), ArrayUtil.get(o, 0));
|
||||||
Assertions.assertEquals(Integer.valueOf(3), ArrayUtil.get(o, 1));
|
Assertions.assertEquals(Integer.valueOf(3), ArrayUtil.get(o, 1));
|
||||||
|
@ -12,8 +12,11 @@
|
|||||||
|
|
||||||
package org.dromara.hutool.core.bean.path;
|
package org.dromara.hutool.core.bean.path;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.dromara.hutool.core.array.ArrayUtil;
|
||||||
import org.dromara.hutool.core.lang.test.bean.ExamInfoDict;
|
import org.dromara.hutool.core.lang.test.bean.ExamInfoDict;
|
||||||
import org.dromara.hutool.core.lang.test.bean.UserInfoDict;
|
import org.dromara.hutool.core.lang.test.bean.UserInfoDict;
|
||||||
|
import org.dromara.hutool.core.map.Dict;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -113,4 +116,52 @@ public class BeanPathGetOrSetValueTest {
|
|||||||
beanPath.setValue(map, "张三");
|
beanPath.setValue(map, "张三");
|
||||||
Assertions.assertEquals("{list=[[null, {name=张三}]]}", map.toString());
|
Assertions.assertEquals("{list=[[null, {name=张三}]]}", map.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void putTest() {
|
||||||
|
final Map<String, Object> map = new HashMap<>();
|
||||||
|
|
||||||
|
final BeanPath beanPath = BeanPath.of("list[1].name");
|
||||||
|
beanPath.setValue(map, "张三");
|
||||||
|
Assertions.assertEquals("{list=[null, {name=张三}]}", map.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void putByPathTest() {
|
||||||
|
final Dict dict = new Dict();
|
||||||
|
BeanPath.of("aa.bb").setValue(dict, "BB");
|
||||||
|
Assertions.assertEquals("{aa={bb=BB}}", dict.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void appendArrayTest(){
|
||||||
|
// issue#3008@Github
|
||||||
|
final MyUser myUser = new MyUser();
|
||||||
|
BeanPath.of("hobby[0]").setValue(myUser, "LOL");
|
||||||
|
BeanPath.of("hobby[1]").setValue(myUser, "KFC");
|
||||||
|
BeanPath.of("hobby[2]").setValue(myUser, "COFFE");
|
||||||
|
|
||||||
|
Assertions.assertEquals("[LOL, KFC, COFFE]", ArrayUtil.toString(myUser.getHobby()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void appendArrayTest2(){
|
||||||
|
// issue#3008@Github
|
||||||
|
final MyUser2 myUser = new MyUser2();
|
||||||
|
BeanPath.of("myUser.hobby[0]").setValue(myUser, "LOL");
|
||||||
|
BeanPath.of("myUser.hobby[1]").setValue(myUser, "KFC");
|
||||||
|
BeanPath.of("myUser.hobby[2]").setValue(myUser, "COFFE");
|
||||||
|
|
||||||
|
Assertions.assertEquals("[LOL, KFC, COFFE]", ArrayUtil.toString(myUser.getMyUser().getHobby()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
static class MyUser {
|
||||||
|
private String[] hobby;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
static class MyUser2 {
|
||||||
|
private MyUser myUser;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,11 +13,6 @@
|
|||||||
package org.dromara.hutool.core.reflect;
|
package org.dromara.hutool.core.reflect;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 反射工具类单元测试
|
* 反射工具类单元测试
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
package org.dromara.hutool.json;
|
package org.dromara.hutool.json;
|
||||||
|
|
||||||
import org.dromara.hutool.core.bean.BeanPathOld;
|
import org.dromara.hutool.core.bean.path.BeanPath;
|
||||||
import org.dromara.hutool.core.convert.ConvertException;
|
import org.dromara.hutool.core.convert.ConvertException;
|
||||||
import org.dromara.hutool.core.convert.Converter;
|
import org.dromara.hutool.core.convert.Converter;
|
||||||
import org.dromara.hutool.core.lang.mutable.MutableEntry;
|
import org.dromara.hutool.core.lang.mutable.MutableEntry;
|
||||||
@ -64,11 +64,11 @@ public interface JSON extends Converter, Cloneable, Serializable {
|
|||||||
*
|
*
|
||||||
* @param expression 表达式
|
* @param expression 表达式
|
||||||
* @return 对象
|
* @return 对象
|
||||||
* @see BeanPathOld#get(Object)
|
* @see BeanPath#getValue(Object)
|
||||||
* @since 4.0.6
|
* @since 4.0.6
|
||||||
*/
|
*/
|
||||||
default Object getByPath(final String expression) {
|
default Object getByPath(final String expression) {
|
||||||
return BeanPathOld.of(expression).get(this);
|
return BeanPath.of(expression).getValue(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -93,7 +93,7 @@ public interface JSON extends Converter, Cloneable, Serializable {
|
|||||||
* @param value 值
|
* @param value 值
|
||||||
*/
|
*/
|
||||||
default void putByPath(final String expression, final Object value) {
|
default void putByPath(final String expression, final Object value) {
|
||||||
BeanPathOld.of(expression).set(this, value);
|
BeanPath.of(expression).setValue(this, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -118,7 +118,7 @@ public interface JSON extends Converter, Cloneable, Serializable {
|
|||||||
* @param expression 表达式
|
* @param expression 表达式
|
||||||
* @param resultType 返回值类型
|
* @param resultType 返回值类型
|
||||||
* @return 对象
|
* @return 对象
|
||||||
* @see BeanPathOld#get(Object)
|
* @see BeanPath#getValue(Object)
|
||||||
* @since 4.0.6
|
* @since 4.0.6
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -340,7 +340,7 @@ public class JWT implements RegisteredPayload<JWT> {
|
|||||||
*
|
*
|
||||||
* <p>此方法会补充如下的header:</p>
|
* <p>此方法会补充如下的header:</p>
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>当用户未定义"typ"时,赋默认值:"JWT"</li>
|
* <li>当用户未定义"typ"时,不设置默认值</li>
|
||||||
* <li>当用户未定义"alg"时,根据传入的{@link JWTSigner}对象类型,赋值对应ID</li>
|
* <li>当用户未定义"alg"时,根据传入的{@link JWTSigner}对象类型,赋值对应ID</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
@ -350,12 +350,6 @@ public class JWT implements RegisteredPayload<JWT> {
|
|||||||
public String sign(final JWTSigner signer) {
|
public String sign(final JWTSigner signer) {
|
||||||
Assert.notNull(signer, () -> new JWTException("No Signer provided!"));
|
Assert.notNull(signer, () -> new JWTException("No Signer provided!"));
|
||||||
|
|
||||||
// 检查tye信息
|
|
||||||
final String type = (String) this.header.getClaim(JWTHeader.TYPE);
|
|
||||||
if (StrUtil.isBlank(type)) {
|
|
||||||
this.header.setType("JWT");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查头信息中是否有算法信息
|
// 检查头信息中是否有算法信息
|
||||||
final String algorithm = (String) this.header.getClaim(JWTHeader.ALGORITHM);
|
final String algorithm = (String) this.header.getClaim(JWTHeader.ALGORITHM);
|
||||||
if (StrUtil.isBlank(algorithm)) {
|
if (StrUtil.isBlank(algorithm)) {
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
package org.dromara.hutool.json.jwt;
|
package org.dromara.hutool.json.jwt;
|
||||||
|
|
||||||
|
import org.dromara.hutool.core.map.MapUtil;
|
||||||
import org.dromara.hutool.json.jwt.signers.JWTSigner;
|
import org.dromara.hutool.json.jwt.signers.JWTSigner;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -29,7 +30,7 @@ public class JWTUtil {
|
|||||||
* @return JWT Token
|
* @return JWT Token
|
||||||
*/
|
*/
|
||||||
public static String createToken(final Map<String, Object> payload, final byte[] key) {
|
public static String createToken(final Map<String, Object> payload, final byte[] key) {
|
||||||
return createToken(null, payload, key);
|
return createToken(MapUtil.of(JWTHeader.TYPE, "JWT"), payload, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,6 +30,7 @@ public class JWTTest {
|
|||||||
public void createHs256Test() {
|
public void createHs256Test() {
|
||||||
final byte[] key = "1234567890".getBytes();
|
final byte[] key = "1234567890".getBytes();
|
||||||
final JWT jwt = JWT.of()
|
final JWT jwt = JWT.of()
|
||||||
|
.setHeader(JWTHeader.TYPE, "JWT")
|
||||||
.setPayload("sub", "1234567890")
|
.setPayload("sub", "1234567890")
|
||||||
.setPayload("name", "looly")
|
.setPayload("name", "looly")
|
||||||
.setPayload("admin", true)
|
.setPayload("admin", true)
|
||||||
@ -70,6 +71,7 @@ public class JWTTest {
|
|||||||
@Test
|
@Test
|
||||||
public void createNoneTest() {
|
public void createNoneTest() {
|
||||||
final JWT jwt = JWT.of()
|
final JWT jwt = JWT.of()
|
||||||
|
.setHeader(JWTHeader.TYPE, "JWT")
|
||||||
.setPayload("sub", "1234567890")
|
.setPayload("sub", "1234567890")
|
||||||
.setPayload("name", "looly")
|
.setPayload("name", "looly")
|
||||||
.setPayload("admin", true)
|
.setPayload("admin", true)
|
||||||
@ -114,6 +116,7 @@ public class JWTTest {
|
|||||||
private String name;
|
private String name;
|
||||||
private Integer age;
|
private Integer age;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void payloadTest() {
|
public void payloadTest() {
|
||||||
|
|
||||||
@ -130,6 +133,7 @@ public class JWTTest {
|
|||||||
map.put("test2", "2");
|
map.put("test2", "2");
|
||||||
final Map<String, Object> payload = new HashMap<String, Object>() {
|
final Map<String, Object> payload = new HashMap<String, Object>() {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
{
|
{
|
||||||
put("username", username);
|
put("username", username);
|
||||||
put("bean", bean);
|
put("bean", bean);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user