mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-05 17:37:59 +08:00
add filter
This commit is contained in:
parent
aa48d3f2ff
commit
6acf0854d8
@ -6,10 +6,12 @@
|
||||
# 5.8.0.M4 (2022-04-16)
|
||||
|
||||
### ❌不兼容特性
|
||||
* 【json 】 【可能兼容问题】JSONArray删除部分构造
|
||||
|
||||
### 🐣新特性
|
||||
* 【core 】 BeanUtil增加toBean重载(pr#598@Gitee)
|
||||
* 【json 】 新增JSONParser
|
||||
* 【json 】 JSON新增在解析时的过滤方法(issue#I52O85@Gitee)
|
||||
|
||||
### 🐞Bug修复
|
||||
|
||||
|
@ -2,6 +2,10 @@ package cn.hutool.json;
|
||||
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.lang.Filter;
|
||||
import cn.hutool.core.lang.mutable.MutablePair;
|
||||
import cn.hutool.core.map.CaseInsensitiveLinkedMap;
|
||||
import cn.hutool.core.map.CaseInsensitiveTreeMap;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.CharUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
@ -10,7 +14,10 @@ import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* 内部JSON工具类,仅用于JSON内部使用
|
||||
@ -26,12 +33,14 @@ public final class InternalJSONUtil {
|
||||
* 如果对象是Number 且是 NaN or infinite,将抛出异常
|
||||
*
|
||||
* @param obj 被检查的对象
|
||||
* @return 检测后的值
|
||||
* @throws JSONException If o is a non-finite number.
|
||||
*/
|
||||
static void testValidity(Object obj) throws JSONException {
|
||||
static Object testValidity(Object obj) throws JSONException {
|
||||
if (false == ObjectUtil.isValidIfNumber(obj)) {
|
||||
throw new JSONException("JSON does not allow non-finite numbers.");
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -123,14 +132,15 @@ public final class InternalJSONUtil {
|
||||
|
||||
/**
|
||||
* 将Property的键转化为JSON形式<br>
|
||||
* 用于识别类似于:com.luxiaolei.package.hutool这类用点隔开的键
|
||||
* 用于识别类似于:com.luxiaolei.package.hutool这类用点隔开的键<br>
|
||||
* 注意:不允许重复键
|
||||
*
|
||||
* @param jsonObject JSONObject
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return JSONObject
|
||||
*/
|
||||
static JSONObject propertyPut(JSONObject jsonObject, Object key, Object value) {
|
||||
static JSONObject propertyPut(JSONObject jsonObject, Object key, Object value, Filter<MutablePair<String, Object>> filter) {
|
||||
final String[] path = StrUtil.splitToArray(Convert.toStr(key), CharUtil.DOT);
|
||||
int last = path.length - 1;
|
||||
JSONObject target = jsonObject;
|
||||
@ -139,11 +149,11 @@ public final class InternalJSONUtil {
|
||||
JSONObject nextTarget = target.getJSONObject(segment);
|
||||
if (nextTarget == null) {
|
||||
nextTarget = new JSONObject(target.getConfig());
|
||||
target.set(segment, nextTarget);
|
||||
target.setOnce(segment, nextTarget, filter);
|
||||
}
|
||||
target = nextTarget;
|
||||
}
|
||||
target.set(path[last], value);
|
||||
target.setOnce(path[last], value, filter);
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
@ -180,4 +190,33 @@ public final class InternalJSONUtil {
|
||||
.setIgnoreNullValue(config.isIgnoreNullValue())
|
||||
.setTransientSupport(config.isTransientSupport());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据配置创建对应的原始Map
|
||||
*
|
||||
* @param capacity 初始大小
|
||||
* @param config JSON配置项,{@code null}则使用默认配置
|
||||
* @return Map
|
||||
*/
|
||||
static Map<String, Object> createRawMap(int capacity, JSONConfig config) {
|
||||
Map<String, Object> rawHashMap;
|
||||
if (null == config) {
|
||||
config = JSONConfig.create();
|
||||
}
|
||||
final Comparator<String> keyComparator = config.getKeyComparator();
|
||||
if (config.isIgnoreCase()) {
|
||||
if (null != keyComparator) {
|
||||
rawHashMap = new CaseInsensitiveTreeMap<>(keyComparator);
|
||||
} else {
|
||||
rawHashMap = new CaseInsensitiveLinkedMap<>(capacity);
|
||||
}
|
||||
} else {
|
||||
if (null != keyComparator) {
|
||||
rawHashMap = new TreeMap<>(keyComparator);
|
||||
} else {
|
||||
rawHashMap = new LinkedHashMap<>(capacity);
|
||||
}
|
||||
}
|
||||
return rawHashMap;
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ import cn.hutool.core.bean.BeanPath;
|
||||
import cn.hutool.core.collection.ArrayIter;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Filter;
|
||||
import cn.hutool.core.lang.mutable.Mutable;
|
||||
import cn.hutool.core.lang.mutable.MutableObj;
|
||||
import cn.hutool.core.lang.mutable.MutablePair;
|
||||
import cn.hutool.core.text.StrJoiner;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
@ -52,7 +54,7 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
|
||||
*/
|
||||
private final JSONConfig config;
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------- Constructor start
|
||||
// region Constructors
|
||||
|
||||
/**
|
||||
* 构造<br>
|
||||
@ -97,52 +99,6 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
|
||||
this.config = ObjectUtil.defaultIfNull(config, JSONConfig::create);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造<br>
|
||||
* 将参数数组中的元素转换为JSON对应的对象加入到JSONArray中
|
||||
*
|
||||
* @param list 初始化的JSON数组
|
||||
*/
|
||||
public JSONArray(Iterable<Object> list) {
|
||||
this();
|
||||
for (Object o : list) {
|
||||
this.add(o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造<br>
|
||||
* 将参数数组中的元素转换为JSON对应的对象加入到JSONArray中
|
||||
*
|
||||
* @param list 初始化的JSON数组
|
||||
*/
|
||||
public JSONArray(Collection<Object> list) {
|
||||
this(list.size());
|
||||
this.addAll(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 {@link JSONTokener} 做为参数构造
|
||||
*
|
||||
* @param x A {@link JSONTokener}
|
||||
* @throws JSONException If there is a syntax error.
|
||||
*/
|
||||
public JSONArray(JSONTokener x) throws JSONException {
|
||||
this();
|
||||
init(x);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从String构造(JSONArray字符串)
|
||||
*
|
||||
* @param source JSON数组字符串
|
||||
* @throws JSONException If there is a syntax error.
|
||||
*/
|
||||
public JSONArray(CharSequence source) throws JSONException {
|
||||
this();
|
||||
init(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从对象构造,忽略{@code null}的值<br>
|
||||
* 支持以下类型的参数:
|
||||
@ -194,10 +150,30 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
|
||||
* @since 4.6.5
|
||||
*/
|
||||
public JSONArray(Object object, JSONConfig jsonConfig) throws JSONException {
|
||||
this(DEFAULT_CAPACITY, jsonConfig);
|
||||
init(object);
|
||||
this(object, jsonConfig, null);
|
||||
}
|
||||
// -------------------------------------------------------------------------------------------------------------------- Constructor end
|
||||
|
||||
/**
|
||||
* 从对象构造<br>
|
||||
* 支持以下类型的参数:
|
||||
*
|
||||
* <pre>
|
||||
* 1. 数组
|
||||
* 2. {@link Iterable}对象
|
||||
* 3. JSON数组字符串
|
||||
* </pre>
|
||||
*
|
||||
* @param object 数组或集合或JSON数组字符串
|
||||
* @param jsonConfig JSON选项
|
||||
* @param filter 键值对过滤编辑器,可以通过实现此接口,完成解析前对值的过滤和修改操作,{@code null}表示不过滤
|
||||
* @throws JSONException 非数组或集合
|
||||
* @since 5.8.0
|
||||
*/
|
||||
public JSONArray(Object object, JSONConfig jsonConfig, Filter<Mutable<Object>> filter) throws JSONException {
|
||||
this(DEFAULT_CAPACITY, jsonConfig);
|
||||
init(object, filter);
|
||||
}
|
||||
// endregion
|
||||
|
||||
@Override
|
||||
public JSONConfig getConfig() {
|
||||
@ -385,7 +361,7 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
|
||||
|
||||
@Override
|
||||
public boolean add(Object e) {
|
||||
return addRaw(JSONUtil.wrap(e, this.config));
|
||||
return addRaw(JSONUtil.wrap(e, this.config), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -456,6 +432,28 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
|
||||
*/
|
||||
@Override
|
||||
public Object set(int index, Object element) {
|
||||
return set(index, element, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加入或者替换JSONArray中指定Index的值,如果index大于JSONArray的长度,将在指定index设置值,之前的位置填充JSONNull.Null
|
||||
*
|
||||
* @param index 位置
|
||||
* @param element 值对象. 可以是以下类型: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
|
||||
* @param filter 过滤器,可以修改值,key(index)无法修改
|
||||
* @return 替换的值,即之前的值
|
||||
* @since 5.8.0
|
||||
*/
|
||||
public Object set(int index, Object element, Filter<MutablePair<Integer, Object>> filter) {
|
||||
// 添加前置过滤,通过MutablePair实现过滤、修改键值对等
|
||||
if (null != filter) {
|
||||
final MutablePair<Integer, Object> pair = new MutablePair<>(index, element);
|
||||
if (filter.accept(pair)) {
|
||||
// 使用修改后的值
|
||||
element = pair.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
if (index >= size()) {
|
||||
add(index, element);
|
||||
}
|
||||
@ -595,11 +593,23 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
|
||||
/**
|
||||
* 原始添加,添加的对象不做任何处理
|
||||
*
|
||||
* @param obj 添加的对象
|
||||
* @param obj 添加的对象
|
||||
* @param filter 键值对过滤编辑器,可以通过实现此接口,完成解析前对值的过滤和修改操作,{@code null}表示不过滤
|
||||
* @return 是否加入成功
|
||||
* @since 5.8.0
|
||||
*/
|
||||
protected boolean addRaw(Object obj) {
|
||||
protected boolean addRaw(Object obj, Filter<Mutable<Object>> filter) {
|
||||
// 添加前置过滤,通过MutablePair实现过滤、修改键值对等
|
||||
if (null != filter) {
|
||||
final Mutable<Object> mutable = new MutableObj<>(obj);
|
||||
if (filter.accept(mutable)) {
|
||||
// 使用修改后的值
|
||||
obj = mutable.get();
|
||||
}else{
|
||||
// 键值对被过滤
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return this.rawList.add(obj);
|
||||
}
|
||||
|
||||
@ -607,10 +617,11 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
|
||||
* 初始化
|
||||
*
|
||||
* @param source 数组或集合或JSON数组字符串
|
||||
* @param filter 键值对过滤编辑器,可以通过实现此接口,完成解析前对值的过滤和修改操作,{@code null}表示不过滤
|
||||
* @throws JSONException 非数组或集合
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private void init(Object source) throws JSONException {
|
||||
private void init(Object source, Filter<Mutable<Object>> filter) throws JSONException {
|
||||
if (null == source) {
|
||||
return;
|
||||
}
|
||||
@ -621,9 +632,9 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
|
||||
serializer.serialize(this, source);
|
||||
} else if (source instanceof CharSequence) {
|
||||
// JSON字符串
|
||||
init((CharSequence) source);
|
||||
initFromStr((CharSequence) source, filter);
|
||||
} else if (source instanceof JSONTokener) {
|
||||
init((JSONTokener) source);
|
||||
initFromTokener((JSONTokener) source, filter);
|
||||
} else {
|
||||
Iterator<?> iter;
|
||||
if (ArrayUtil.isArray(source)) {// 数组
|
||||
@ -641,7 +652,7 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
|
||||
next = iter.next();
|
||||
// 检查循环引用
|
||||
if (next != source) {
|
||||
this.add(next);
|
||||
this.addRaw(JSONUtil.wrap(next, this.config), filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -652,19 +663,20 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
|
||||
*
|
||||
* @param source JSON字符串
|
||||
*/
|
||||
private void init(CharSequence source) {
|
||||
private void initFromStr(CharSequence source, Filter<Mutable<Object>> filter) {
|
||||
if (null != source) {
|
||||
init(new JSONTokener(StrUtil.trim(source), this.config));
|
||||
initFromTokener(new JSONTokener(StrUtil.trim(source), this.config), filter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*
|
||||
* @param x {@link JSONTokener}
|
||||
* @param x {@link JSONTokener}
|
||||
* @param filter 键值对过滤编辑器,可以通过实现此接口,完成解析前对值的过滤和修改操作,{@code null}表示不过滤
|
||||
*/
|
||||
private void init(JSONTokener x) {
|
||||
JSONParser.of(x).parseTo(this);
|
||||
private void initFromTokener(JSONTokener x, Filter<Mutable<Object>> filter) {
|
||||
JSONParser.of(x).parseTo(this, filter);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------- Private method end
|
||||
}
|
||||
|
@ -6,9 +6,7 @@ import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.lang.Filter;
|
||||
import cn.hutool.core.lang.mutable.MutablePair;
|
||||
import cn.hutool.core.map.CaseInsensitiveLinkedMap;
|
||||
import cn.hutool.core.map.CaseInsensitiveMap;
|
||||
import cn.hutool.core.map.CaseInsensitiveTreeMap;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.map.MapWrapper;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
@ -26,12 +24,9 @@ import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* JSON对象<br>
|
||||
@ -119,8 +114,8 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
|
||||
* @since 4.1.19
|
||||
*/
|
||||
public JSONObject(int capacity, JSONConfig config) {
|
||||
super(createRaw(capacity, config));
|
||||
this.config = config;
|
||||
super(InternalJSONUtil.createRawMap(capacity, ObjectUtil.defaultIfNull(config, JSONConfig.create())));
|
||||
this.config = ObjectUtil.defaultIfNull(config, JSONConfig.create());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -198,8 +193,30 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
|
||||
* @since 4.2.2
|
||||
*/
|
||||
public JSONObject(Object source, JSONConfig config) {
|
||||
this(source, config, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建JSONObject,规则如下:
|
||||
* <ol>
|
||||
* <li>value为Map,将键值对加入JSON对象</li>
|
||||
* <li>value为JSON字符串(CharSequence),使用JSONTokener解析</li>
|
||||
* <li>value为JSONTokener,直接解析</li>
|
||||
* <li>value为普通JavaBean,如果为普通的JavaBean,调用其getters方法(getXXX或者isXXX)获得值,加入到JSON对象。例如:如果JavaBean对象中有个方法getName(),值为"张三",获得的键值对为:name: "张三"</li>
|
||||
* </ol>
|
||||
* <p>
|
||||
* 如果给定值为Map,将键值对加入JSON对象;<br>
|
||||
* 如果为普通的JavaBean,调用其getters方法(getXXX或者isXXX)获得值,加入到JSON对象<br>
|
||||
* 例如:如果JavaBean对象中有个方法getName(),值为"张三",获得的键值对为:name: "张三"
|
||||
*
|
||||
* @param source JavaBean或者Map对象或者String
|
||||
* @param config JSON配置文件,{@code null}则使用默认配置
|
||||
* @param filter 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@code null}表示不过滤
|
||||
* @since 5.8.0
|
||||
*/
|
||||
public JSONObject(Object source, JSONConfig config, Filter<MutablePair<String, Object>> filter) {
|
||||
this(DEFAULT_CAPACITY, config);
|
||||
init(source);
|
||||
init(source, filter);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -219,7 +236,7 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
|
||||
public JSONObject(Object obj, String... names) {
|
||||
this();
|
||||
if (ArrayUtil.isEmpty(names)) {
|
||||
init(obj);
|
||||
init(obj, null);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -346,17 +363,47 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
|
||||
* @throws JSONException 值是无穷数字抛出此异常
|
||||
*/
|
||||
public JSONObject set(String key, Object value) throws JSONException {
|
||||
return set(key, value, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置键值对到JSONObject中,在忽略null模式下,如果值为{@code null},将此键移除
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值对象. 可以是以下类型: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
|
||||
* @param filter 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@code null}表示不过滤
|
||||
* @return this.
|
||||
* @throws JSONException 值是无穷数字抛出此异常
|
||||
* @since 5.8.0
|
||||
*/
|
||||
public JSONObject set(String key, Object value, Filter<MutablePair<String, Object>> filter, boolean checkDuplicate) throws JSONException {
|
||||
if (null == key) {
|
||||
return this;
|
||||
}
|
||||
|
||||
// 添加前置过滤,通过MutablePair实现过滤、修改键值对等
|
||||
if (null != filter) {
|
||||
final MutablePair<String, Object> pair = new MutablePair<>(key, value);
|
||||
if (filter.accept(pair)) {
|
||||
// 使用修改后的键值对
|
||||
key = pair.getKey();
|
||||
value = pair.getValue();
|
||||
}else{
|
||||
// 键值对被过滤
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
final boolean ignoreNullValue = this.config.isIgnoreNullValue();
|
||||
if (ObjectUtil.isNull(value) && ignoreNullValue) {
|
||||
// 忽略值模式下如果值为空清除key
|
||||
this.remove(key);
|
||||
} else {
|
||||
InternalJSONUtil.testValidity(value);
|
||||
super.put(key, JSONUtil.wrap(value, this.config));
|
||||
if(checkDuplicate && containsKey(key)){
|
||||
throw new JSONException("Duplicate key \"{}\"", key);
|
||||
}
|
||||
|
||||
super.put(key, JSONUtil.wrap(InternalJSONUtil.testValidity(value), this.config));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@ -370,13 +417,20 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
|
||||
* @throws JSONException 值是无穷数字、键重复抛出异常
|
||||
*/
|
||||
public JSONObject putOnce(String key, Object value) throws JSONException {
|
||||
if (key != null) {
|
||||
if (containsKey(key)) {
|
||||
throw new JSONException("Duplicate key \"{}\"", key);
|
||||
}
|
||||
this.set(key, value);
|
||||
}
|
||||
return this;
|
||||
return setOnce(key, value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 一次性Put 键值对,如果key已经存在抛出异常,如果键值中有null值,忽略
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值对象,可以是以下类型: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
|
||||
* @return this.
|
||||
* @throws JSONException 值是无穷数字、键重复抛出异常
|
||||
* @since 5.8.0
|
||||
*/
|
||||
public JSONObject setOnce(String key, Object value, Filter<MutablePair<String, Object>> filter) throws JSONException {
|
||||
return set(key, value, filter, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -564,9 +618,10 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
|
||||
* </ol>
|
||||
*
|
||||
* @param source JavaBean或者Map对象或者String
|
||||
* @param filter 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private void init(Object source) {
|
||||
private void init(Object source, Filter<MutablePair<String, Object>> filter) {
|
||||
if (null == source) {
|
||||
return;
|
||||
}
|
||||
@ -586,22 +641,22 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
|
||||
if (source instanceof Map) {
|
||||
// Map
|
||||
for (final Entry<?, ?> e : ((Map<?, ?>) source).entrySet()) {
|
||||
this.set(Convert.toStr(e.getKey()), e.getValue());
|
||||
this.set(Convert.toStr(e.getKey()), e.getValue(), filter, false);
|
||||
}
|
||||
} else if (source instanceof Map.Entry) {
|
||||
final Map.Entry entry = (Map.Entry) source;
|
||||
this.set(Convert.toStr(entry.getKey()), entry.getValue());
|
||||
this.set(Convert.toStr(entry.getKey()), entry.getValue(), filter, false);
|
||||
} else if (source instanceof CharSequence) {
|
||||
// 可能为JSON字符串
|
||||
init((CharSequence) source);
|
||||
initFromStr((CharSequence) source, filter);
|
||||
} else if (source instanceof JSONTokener) {
|
||||
// JSONTokener
|
||||
init((JSONTokener) source);
|
||||
initFromTokener((JSONTokener) source, filter);
|
||||
} else if (source instanceof ResourceBundle) {
|
||||
// JSONTokener
|
||||
init((ResourceBundle) source);
|
||||
initFromResourceBundle((ResourceBundle) source, filter);
|
||||
} else if (BeanUtil.isReadableBean(source.getClass())) {
|
||||
// 普通Bean
|
||||
// 普通Bean,过滤器无效
|
||||
this.populateMap(source);
|
||||
} else {
|
||||
// 不支持对象类型转换为JSONObject
|
||||
@ -613,14 +668,15 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
|
||||
* 初始化
|
||||
*
|
||||
* @param bundle ResourceBundle
|
||||
* @param filter 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@code null}表示不过滤
|
||||
* @since 5.3.1
|
||||
*/
|
||||
private void init(ResourceBundle bundle) {
|
||||
private void initFromResourceBundle(ResourceBundle bundle, Filter<MutablePair<String, Object>> filter) {
|
||||
Enumeration<String> keys = bundle.getKeys();
|
||||
while (keys.hasMoreElements()) {
|
||||
String key = keys.nextElement();
|
||||
if (key != null) {
|
||||
InternalJSONUtil.propertyPut(this, key, bundle.getString(key));
|
||||
InternalJSONUtil.propertyPut(this, key, bundle.getString(key), filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -629,53 +685,26 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
|
||||
* 初始化,可以判断字符串为JSON或者XML
|
||||
*
|
||||
* @param source JSON字符串
|
||||
* @param filter 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@code null}表示不过滤
|
||||
*/
|
||||
private void init(CharSequence source) {
|
||||
private void initFromStr(CharSequence source, Filter<MutablePair<String, Object>> filter) {
|
||||
final String jsonStr = StrUtil.trim(source);
|
||||
if (StrUtil.startWith(jsonStr, '<')) {
|
||||
// 可能为XML
|
||||
XML.toJSONObject(this, jsonStr, false);
|
||||
return;
|
||||
}
|
||||
init(new JSONTokener(StrUtil.trim(source), this.config));
|
||||
initFromTokener(new JSONTokener(StrUtil.trim(source), this.config), filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*
|
||||
* @param x JSONTokener
|
||||
* @param x JSONTokener
|
||||
* @param filter 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作
|
||||
*/
|
||||
private void init(JSONTokener x) {
|
||||
JSONParser.of(x).parseTo(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据配置创建对应的原始Map
|
||||
*
|
||||
* @param capacity 初始大小
|
||||
* @param config JSON配置项,{@code null}则使用默认配置
|
||||
* @return Map
|
||||
*/
|
||||
private static Map<String, Object> createRaw(int capacity, JSONConfig config) {
|
||||
Map<String, Object> rawHashMap;
|
||||
if (null == config) {
|
||||
config = JSONConfig.create();
|
||||
}
|
||||
final Comparator<String> keyComparator = config.getKeyComparator();
|
||||
if (config.isIgnoreCase()) {
|
||||
if (null != keyComparator) {
|
||||
rawHashMap = new CaseInsensitiveTreeMap<>(keyComparator);
|
||||
} else {
|
||||
rawHashMap = new CaseInsensitiveLinkedMap<>(capacity);
|
||||
}
|
||||
} else {
|
||||
if (null != keyComparator) {
|
||||
rawHashMap = new TreeMap<>(keyComparator);
|
||||
} else {
|
||||
rawHashMap = new LinkedHashMap<>(capacity);
|
||||
}
|
||||
}
|
||||
return rawHashMap;
|
||||
private void initFromTokener(JSONTokener x, Filter<MutablePair<String, Object>> filter) {
|
||||
JSONParser.of(x).parseTo(this, filter);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------- Private method end
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
package cn.hutool.json;
|
||||
|
||||
import cn.hutool.core.lang.Filter;
|
||||
import cn.hutool.core.lang.mutable.Mutable;
|
||||
import cn.hutool.core.lang.mutable.MutablePair;
|
||||
|
||||
/**
|
||||
* JSON字符串解析器
|
||||
*
|
||||
@ -7,7 +11,6 @@ package cn.hutool.json;
|
||||
* @since 5.8.0
|
||||
*/
|
||||
public class JSONParser {
|
||||
private final JSONTokener tokener;
|
||||
|
||||
/**
|
||||
* 创建JSONParser
|
||||
@ -19,6 +22,8 @@ public class JSONParser {
|
||||
return new JSONParser(tokener);
|
||||
}
|
||||
|
||||
private final JSONTokener tokener;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
@ -28,12 +33,14 @@ public class JSONParser {
|
||||
this.tokener = tokener;
|
||||
}
|
||||
|
||||
// region parseTo
|
||||
/**
|
||||
* 解析{@link JSONTokener}中的字符到目标的{@link JSONObject}中
|
||||
*
|
||||
* @param jsonObject {@link JSONObject}
|
||||
* @param filter 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@code null}表示不过滤
|
||||
*/
|
||||
public void parseTo(JSONObject jsonObject) {
|
||||
public void parseTo(JSONObject jsonObject, Filter<MutablePair<String, Object>> filter) {
|
||||
final JSONTokener tokener = this.tokener;
|
||||
|
||||
char c;
|
||||
@ -60,7 +67,8 @@ public class JSONParser {
|
||||
if (c != ':') {
|
||||
throw tokener.syntaxError("Expected a ':' after a key");
|
||||
}
|
||||
jsonObject.putOnce(key, tokener.nextValue());
|
||||
|
||||
jsonObject.setOnce(key, tokener.nextValue(), filter);
|
||||
|
||||
// Pairs are separated by ','.
|
||||
|
||||
@ -85,7 +93,7 @@ public class JSONParser {
|
||||
*
|
||||
* @param jsonArray {@link JSONArray}
|
||||
*/
|
||||
public void parseTo(JSONArray jsonArray) {
|
||||
public void parseTo(JSONArray jsonArray, Filter<Mutable<Object>> filter) {
|
||||
final JSONTokener x = this.tokener;
|
||||
|
||||
if (x.nextClean() != '[') {
|
||||
@ -96,10 +104,10 @@ public class JSONParser {
|
||||
for (; ; ) {
|
||||
if (x.nextClean() == ',') {
|
||||
x.back();
|
||||
jsonArray.addRaw(JSONNull.NULL);
|
||||
jsonArray.addRaw(JSONNull.NULL, filter);
|
||||
} else {
|
||||
x.back();
|
||||
jsonArray.addRaw(x.nextValue());
|
||||
jsonArray.addRaw(x.nextValue(), filter);
|
||||
}
|
||||
switch (x.nextClean()) {
|
||||
case ',':
|
||||
@ -116,4 +124,5 @@ public class JSONParser {
|
||||
}
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
}
|
||||
|
@ -218,7 +218,7 @@ public class JSONArrayTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putTest(){
|
||||
public void putToIndexTest(){
|
||||
final JSONArray jsonArray = new JSONArray();
|
||||
jsonArray.put(3, "test");
|
||||
// 第三个位置插入值,0~2都是null
|
||||
@ -279,4 +279,30 @@ public class JSONArrayTest {
|
||||
|
||||
Assert.assertEquals("[null]", array.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseFilterTest() {
|
||||
String jsonArr = "[{\"id\":111,\"name\":\"test1\"},{\"id\":112,\"name\":\"test2\"}]";
|
||||
//noinspection MismatchedQueryAndUpdateOfCollection
|
||||
final JSONArray array = new JSONArray(jsonArr, null, (mutable) -> mutable.get().toString().contains("111"));
|
||||
Assert.assertEquals(1, array.size());
|
||||
Assert.assertTrue(array.getJSONObject(0).containsKey("id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseFilterEditTest() {
|
||||
String jsonArr = "[{\"id\":111,\"name\":\"test1\"},{\"id\":112,\"name\":\"test2\"}]";
|
||||
//noinspection MismatchedQueryAndUpdateOfCollection
|
||||
final JSONArray array = new JSONArray(jsonArr, null, (mutable) -> {
|
||||
final JSONObject o = new JSONObject(mutable.get());
|
||||
if("111".equals(o.getStr("id"))){
|
||||
o.set("name", "test1_edit");
|
||||
}
|
||||
mutable.set(o);
|
||||
return true;
|
||||
});
|
||||
Assert.assertEquals(2, array.size());
|
||||
Assert.assertTrue(array.getJSONObject(0).containsKey("id"));
|
||||
Assert.assertEquals("test1_edit", array.getJSONObject(0).get("name"));
|
||||
}
|
||||
}
|
||||
|
@ -682,4 +682,26 @@ public class JSONObjectTest {
|
||||
});
|
||||
Assert.assertEquals("{\"a\":\"\",\"b\":\"value2\"}", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseFilterTest() {
|
||||
String jsonStr = "{\"b\":\"value2\",\"c\":\"value3\",\"a\":\"value1\", \"d\": true, \"e\": null}";
|
||||
//noinspection MismatchedQueryAndUpdateOfCollection
|
||||
JSONObject jsonObject = new JSONObject(jsonStr, null, (pair)-> "b".equals(pair.getKey()));
|
||||
Assert.assertEquals(1, jsonObject.size());
|
||||
Assert.assertEquals("value2", jsonObject.get("b"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseFilterEditTest() {
|
||||
String jsonStr = "{\"b\":\"value2\",\"c\":\"value3\",\"a\":\"value1\", \"d\": true, \"e\": null}";
|
||||
//noinspection MismatchedQueryAndUpdateOfCollection
|
||||
JSONObject jsonObject = new JSONObject(jsonStr, null, (pair)-> {
|
||||
if("b".equals(pair.getKey())){
|
||||
pair.setValue(pair.getValue() + "_edit");
|
||||
}
|
||||
return true;
|
||||
});
|
||||
Assert.assertEquals("value2_edit", jsonObject.get("b"));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user