add JSONParser

This commit is contained in:
Looly 2024-09-13 00:55:35 +08:00
parent 7debdcef60
commit 1f705e0e1f
16 changed files with 219 additions and 109 deletions

View File

@ -143,7 +143,7 @@ public final class InternalJSONUtil {
* @param value * @param value
* @param predicate 属性过滤器{@link Predicate#test(Object)}{@code true}保留 * @param predicate 属性过滤器{@link Predicate#test(Object)}{@code true}保留
*/ */
public static void propertyPut(final JSONObject jsonObject, final Object key, final Object value, final Predicate<MutableEntry<String, Object>> predicate) { public static void propertyPut(final JSONObject jsonObject, final Object key, final Object value, final Predicate<MutableEntry<Object, Object>> predicate) {
final String[] path = SplitUtil.splitToArray(ConvertUtil.toStr(key), StrUtil.DOT); final String[] path = SplitUtil.splitToArray(ConvertUtil.toStr(key), StrUtil.DOT);
final int last = path.length - 1; final int last = path.length - 1;
JSONObject target = jsonObject; JSONObject target = jsonObject;

View File

@ -164,7 +164,7 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
* @throws JSONException 非数组或集合 * @throws JSONException 非数组或集合
* @since 5.8.0 * @since 5.8.0
*/ */
public JSONArray(final Object object, final JSONConfig jsonConfig, final Predicate<Mutable<Object>> predicate) throws JSONException { public JSONArray(final Object object, final JSONConfig jsonConfig, final Predicate<MutableEntry<Object, Object>> predicate) throws JSONException {
this(DEFAULT_CAPACITY, jsonConfig); this(DEFAULT_CAPACITY, jsonConfig);
JSONArrayMapper.of(object, predicate).mapTo(this); JSONArrayMapper.of(object, predicate).mapTo(this);
} }
@ -201,7 +201,11 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
@Override @Override
public Object get(final int index) { public Object get(final int index) {
return this.rawList.get(index); Object value = this.rawList.get(index);
if(value instanceof JSONPrimitive){
value = ((JSONPrimitive) value).getValue();
}
return value;
} }
@Override @Override

View File

@ -152,7 +152,7 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
* @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@code null}表示不过滤{@link Predicate#test(Object)}{@code true}保留 * @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@code null}表示不过滤{@link Predicate#test(Object)}{@code true}保留
* @since 5.8.0 * @since 5.8.0
*/ */
public JSONObject(final Object source, final JSONConfig config, final Predicate<MutableEntry<String, Object>> predicate) { public JSONObject(final Object source, final JSONConfig config, final Predicate<MutableEntry<Object, Object>> predicate) {
this(DEFAULT_CAPACITY, config); this(DEFAULT_CAPACITY, config);
JSONObjectMapper.of(source, predicate).mapTo(this); JSONObjectMapper.of(source, predicate).mapTo(this);
} }
@ -200,7 +200,16 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
@Override @Override
public Object getObj(final String key, final Object defaultValue) { public Object getObj(final String key, final Object defaultValue) {
return this.getOrDefault(key, defaultValue); return getOrDefault(key, defaultValue);
}
@Override
public Object getOrDefault(final Object key, final Object defaultValue) {
Object value = super.getOrDefault(key, defaultValue);
if(value instanceof JSONPrimitive){
value = ((JSONPrimitive) value).getValue();
}
return value;
} }
/** /**
@ -268,7 +277,7 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
* @throws JSONException 值是无穷数字键重复抛出异常 * @throws JSONException 值是无穷数字键重复抛出异常
* @since 5.8.0 * @since 5.8.0
*/ */
public JSONObject set(final String key, final Object value, final Predicate<MutableEntry<String, Object>> predicate) throws JSONException { public JSONObject set(final String key, final Object value, final Predicate<MutableEntry<Object, Object>> predicate) throws JSONException {
put(key, value, predicate, config().isCheckDuplicate()); put(key, value, predicate, config().isCheckDuplicate());
return this; return this;
} }
@ -284,7 +293,7 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
* @throws JSONException 值是无穷数字抛出此异常 * @throws JSONException 值是无穷数字抛出此异常
* @since 5.8.0 * @since 5.8.0
*/ */
public JSONObject set(final String key, final Object value, final Predicate<MutableEntry<String, Object>> predicate, final boolean checkDuplicate) throws JSONException { public JSONObject set(final String key, final Object value, final Predicate<MutableEntry<Object, Object>> predicate, final boolean checkDuplicate) throws JSONException {
put(key, value, predicate, checkDuplicate); put(key, value, predicate, checkDuplicate);
return this; return this;
} }
@ -343,13 +352,13 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
* @throws JSONException 如果给定键为{@code null}或者键对应的值存在且为非JSONArray * @throws JSONException 如果给定键为{@code null}或者键对应的值存在且为非JSONArray
* @since 6.0.0 * @since 6.0.0
*/ */
public JSONObject append(String key, Object value, final Predicate<MutableEntry<String, Object>> predicate) throws JSONException { public JSONObject append(String key, Object value, final Predicate<MutableEntry<Object, Object>> predicate) throws JSONException {
// 添加前置过滤通过MutablePair实现过滤修改键值对等 // 添加前置过滤通过MutablePair实现过滤修改键值对等
if (null != predicate) { if (null != predicate) {
final MutableEntry<String, Object> pair = new MutableEntry<>(key, value); final MutableEntry<Object, Object> pair = new MutableEntry<>(key, value);
if (predicate.test(pair)) { if (predicate.test(pair)) {
// 使用修改后的键值对 // 使用修改后的键值对
key = pair.getKey(); key = (String) pair.getKey();
value = pair.getValue(); value = pair.getValue();
} else { } else {
// 键值对被过滤 // 键值对被过滤
@ -465,17 +474,17 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
* @throws JSONException 值是无穷数字抛出此异常 * @throws JSONException 值是无穷数字抛出此异常
* @since 5.8.0 * @since 5.8.0
*/ */
private Object put(String key, Object value, final Predicate<MutableEntry<String, Object>> predicate, final boolean checkDuplicate) throws JSONException { private Object put(String key, Object value, final Predicate<MutableEntry<Object, Object>> predicate, final boolean checkDuplicate) throws JSONException {
if (null == key) { if (null == key) {
return null; return null;
} }
// 添加前置过滤通过MutablePair实现过滤修改键值对等 // 添加前置过滤通过MutablePair实现过滤修改键值对等
if (null != predicate) { if (null != predicate) {
final MutableEntry<String, Object> pair = new MutableEntry<>(key, value); final MutableEntry<Object, Object> pair = new MutableEntry<>(key, value);
if (predicate.test(pair)) { if (predicate.test(pair)) {
// 使用修改后的键值对 // 使用修改后的键值对
key = pair.getKey(); key = (String) pair.getKey();
value = pair.getValue(); value = pair.getValue();
} else { } else {
// 键值对被过滤 // 键值对被过滤

View File

@ -24,6 +24,7 @@ import org.dromara.hutool.json.writer.JSONWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.Writer; import java.io.Writer;
import java.lang.reflect.Type;
import java.util.function.Predicate; import java.util.function.Predicate;
/** /**
@ -107,6 +108,11 @@ public class JSONPrimitive implements JSON {
return 1; return 1;
} }
@Override
public <T> T convert(final Type targetType, final Object value, final T defaultValue) {
return JSON.super.convert(targetType, this.value, defaultValue);
}
@Override @Override
public Writer write(final Writer writer, final int indentFactor, final int indent, final Predicate<MutableEntry<Object, Object>> predicate) throws JSONException { public Writer write(final Writer writer, final int indentFactor, final int indent, final Predicate<MutableEntry<Object, Object>> predicate) throws JSONException {
final Object value = this.value; final Object value = this.value;

View File

@ -30,7 +30,7 @@ import org.dromara.hutool.core.reflect.TypeUtil;
import org.dromara.hutool.core.reflect.kotlin.KClassUtil; import org.dromara.hutool.core.reflect.kotlin.KClassUtil;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.json.*; import org.dromara.hutool.json.*;
import org.dromara.hutool.json.reader.OldJSONParser; import org.dromara.hutool.json.reader.JSONParser;
import org.dromara.hutool.json.reader.JSONTokener; import org.dromara.hutool.json.reader.JSONTokener;
import org.dromara.hutool.json.serializer.*; import org.dromara.hutool.json.serializer.*;
@ -202,16 +202,8 @@ public class JSONConverter implements Converter, Serializable {
} }
// RFC8259JSON字符串值number, boolean, or null // RFC8259JSON字符串值number, boolean, or null
final OldJSONParser jsonParser = OldJSONParser.of(new JSONTokener(jsonStr), config); final JSONParser jsonParser = JSONParser.of(new JSONTokener(jsonStr), config);
final Object value = jsonParser.nextValue(); return jsonParser.parse();
if (jsonParser.getTokener().nextClean() != JSONTokener.EOF) {
// 对于用户提供的未转义字符串导致解析未结束报错
throw new JSONException("JSON format error: {}", jsonStr);
}
if(null == value || value instanceof JSON){
return (JSON) value;
}
return new JSONPrimitive(value, config);
} }
// ----------------------------------------------------------- Private method start // ----------------------------------------------------------- Private method start

View File

@ -19,12 +19,12 @@ package org.dromara.hutool.json.mapper;
import org.dromara.hutool.core.array.ArrayUtil; import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.collection.iter.ArrayIter; import org.dromara.hutool.core.collection.iter.ArrayIter;
import org.dromara.hutool.core.io.IoUtil; import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.lang.mutable.Mutable; import org.dromara.hutool.core.lang.mutable.MutableEntry;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.json.JSONArray; import org.dromara.hutool.json.JSONArray;
import org.dromara.hutool.json.JSONConfig; import org.dromara.hutool.json.JSONConfig;
import org.dromara.hutool.json.JSONException; import org.dromara.hutool.json.JSONException;
import org.dromara.hutool.json.reader.OldJSONParser; import org.dromara.hutool.json.reader.JSONParser;
import org.dromara.hutool.json.reader.JSONTokener; import org.dromara.hutool.json.reader.JSONTokener;
import org.dromara.hutool.json.serializer.JSONSerializer; import org.dromara.hutool.json.serializer.JSONSerializer;
import org.dromara.hutool.json.serializer.SerializerManager; import org.dromara.hutool.json.serializer.SerializerManager;
@ -58,12 +58,12 @@ public class JSONArrayMapper {
* @param predicate 值过滤编辑器可以通过实现此接口完成解析前对值的过滤和修改操作{@code null}表示不过滤{@link Predicate#test(Object)}{@code true}保留 * @param predicate 值过滤编辑器可以通过实现此接口完成解析前对值的过滤和修改操作{@code null}表示不过滤{@link Predicate#test(Object)}{@code true}保留
* @return ObjectMapper * @return ObjectMapper
*/ */
public static JSONArrayMapper of(final Object source, final Predicate<Mutable<Object>> predicate) { public static JSONArrayMapper of(final Object source, final Predicate<MutableEntry<Object, Object>> predicate) {
return new JSONArrayMapper(source, predicate); return new JSONArrayMapper(source, predicate);
} }
private final Object source; private final Object source;
private final Predicate<Mutable<Object>> predicate; private final Predicate<MutableEntry<Object, Object>> predicate;
/** /**
* 构造 * 构造
@ -71,7 +71,7 @@ public class JSONArrayMapper {
* @param source 来源对象 * @param source 来源对象
* @param predicate 值过滤编辑器可以通过实现此接口完成解析前对值的过滤和修改操作{@code null}表示不过滤{@link Predicate#test(Object)}{@code true}保留 * @param predicate 值过滤编辑器可以通过实现此接口完成解析前对值的过滤和修改操作{@code null}表示不过滤{@link Predicate#test(Object)}{@code true}保留
*/ */
public JSONArrayMapper(final Object source, final Predicate<Mutable<Object>> predicate) { public JSONArrayMapper(final Object source, final Predicate<MutableEntry<Object, Object>> predicate) {
this.source = source; this.source = source;
this.predicate = predicate; this.predicate = predicate;
} }
@ -82,7 +82,6 @@ public class JSONArrayMapper {
* @param jsonArray 目标{@link JSONArray} * @param jsonArray 目标{@link JSONArray}
* @throws JSONException 非数组或集合 * @throws JSONException 非数组或集合
*/ */
@SuppressWarnings("unchecked")
public void mapTo(final JSONArray jsonArray) throws JSONException { public void mapTo(final JSONArray jsonArray) throws JSONException {
final Object source = this.source; final Object source = this.source;
if (null == source) { if (null == source) {
@ -98,8 +97,8 @@ public class JSONArrayMapper {
if (source instanceof JSONTokener) { if (source instanceof JSONTokener) {
mapFromTokener((JSONTokener) source, JSONConfig.of(), jsonArray); mapFromTokener((JSONTokener) source, JSONConfig.of(), jsonArray);
}if (source instanceof OldJSONParser) { }if (source instanceof JSONParser) {
((OldJSONParser)source).parseTo(jsonArray, this.predicate); ((JSONParser)source).parseTo(jsonArray);
} else if (source instanceof CharSequence) { } else if (source instanceof CharSequence) {
// JSON字符串 // JSON字符串
mapFromStr((CharSequence) source, jsonArray); mapFromStr((CharSequence) source, jsonArray);
@ -139,7 +138,16 @@ public class JSONArrayMapper {
next = iter.next(); next = iter.next();
// 检查循环引用 // 检查循环引用
if (next != source) { if (next != source) {
jsonArray.add(next, predicate); if(null != this.predicate){
final MutableEntry<Object, Object> entry = MutableEntry.of(jsonArray.size(), next);
if (predicate.test(entry)) {
// 使用修改后的键值对
next = entry.getValue();
jsonArray.add(next);
}
}else {
jsonArray.add(next);
}
} }
} }
} }
@ -164,6 +172,6 @@ public class JSONArrayMapper {
* @param jsonArray {@link JSONArray} * @param jsonArray {@link JSONArray}
*/ */
private void mapFromTokener(final JSONTokener x, final JSONConfig config, final JSONArray jsonArray) { private void mapFromTokener(final JSONTokener x, final JSONConfig config, final JSONArray jsonArray) {
OldJSONParser.of(x, config).parseTo(jsonArray, this.predicate); JSONParser.of(x, config).setPredicate(this.predicate).parseTo(jsonArray);
} }
} }

View File

@ -25,7 +25,7 @@ import org.dromara.hutool.core.lang.mutable.MutableEntry;
import org.dromara.hutool.core.reflect.method.MethodUtil; import org.dromara.hutool.core.reflect.method.MethodUtil;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.json.*; import org.dromara.hutool.json.*;
import org.dromara.hutool.json.reader.OldJSONParser; import org.dromara.hutool.json.reader.JSONParser;
import org.dromara.hutool.json.reader.JSONTokener; import org.dromara.hutool.json.reader.JSONTokener;
import org.dromara.hutool.json.serializer.JSONSerializer; import org.dromara.hutool.json.serializer.JSONSerializer;
import org.dromara.hutool.json.serializer.SerializerManager; import org.dromara.hutool.json.serializer.SerializerManager;
@ -66,12 +66,12 @@ public class JSONObjectMapper {
* @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@link Predicate#test(Object)}{@code true}保留 * @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@link Predicate#test(Object)}{@code true}保留
* @return ObjectMapper * @return ObjectMapper
*/ */
public static JSONObjectMapper of(final Object source, final Predicate<MutableEntry<String, Object>> predicate) { public static JSONObjectMapper of(final Object source, final Predicate<MutableEntry<Object, Object>> predicate) {
return new JSONObjectMapper(source, predicate); return new JSONObjectMapper(source, predicate);
} }
private final Object source; private final Object source;
private final Predicate<MutableEntry<String, Object>> predicate; private final Predicate<MutableEntry<Object, Object>> predicate;
/** /**
* 构造 * 构造
@ -79,7 +79,7 @@ public class JSONObjectMapper {
* @param source 来源对象 * @param source 来源对象
* @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@link Predicate#test(Object)}{@code true}保留 * @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@link Predicate#test(Object)}{@code true}保留
*/ */
public JSONObjectMapper(final Object source, final Predicate<MutableEntry<String, Object>> predicate) { public JSONObjectMapper(final Object source, final Predicate<MutableEntry<Object, Object>> predicate) {
this.source = source; this.source = source;
this.predicate = predicate; this.predicate = predicate;
} }
@ -111,9 +111,9 @@ public class JSONObjectMapper {
if (source instanceof JSONTokener) { if (source instanceof JSONTokener) {
// JSONTokener // JSONTokener
mapFromTokener((JSONTokener) source, jsonObject.config(), jsonObject); mapFromTokener((JSONTokener) source, jsonObject.config(), jsonObject);
}if (source instanceof OldJSONParser) { }if (source instanceof JSONParser) {
// JSONParser // JSONParser
((OldJSONParser) source).parseTo(jsonObject, this.predicate); ((JSONParser) source).parseTo(jsonObject);
} else if (source instanceof Map) { } else if (source instanceof Map) {
// Map // Map
for (final Map.Entry<?, ?> e : ((Map<?, ?>) source).entrySet()) { for (final Map.Entry<?, ?> e : ((Map<?, ?>) source).entrySet()) {
@ -180,7 +180,7 @@ public class JSONObjectMapper {
JSONXMLParser.of(ParseConfig.of(), this.predicate).parseJSONObject(jsonStr, jsonObject); JSONXMLParser.of(ParseConfig.of(), this.predicate).parseJSONObject(jsonStr, jsonObject);
return; return;
} }
mapFromTokener(new JSONTokener(StrUtil.trim(source)), jsonObject.config(), jsonObject); mapFromTokener(new JSONTokener(source), jsonObject.config(), jsonObject);
} }
/** /**
@ -191,7 +191,7 @@ public class JSONObjectMapper {
* @param jsonObject {@link JSONObject} * @param jsonObject {@link JSONObject}
*/ */
private void mapFromTokener(final JSONTokener x, final JSONConfig config, final JSONObject jsonObject) { private void mapFromTokener(final JSONTokener x, final JSONConfig config, final JSONObject jsonObject) {
OldJSONParser.of(x, config).parseTo(jsonObject, this.predicate); JSONParser.of(x, config).setPredicate(this.predicate).parseTo(jsonObject);
} }
/** /**

View File

@ -24,10 +24,12 @@ import java.util.function.Predicate;
/** /**
* JSON字符串解析器实现 * JSON字符串解析器实现
* <ul> * <pre>{@code
* <li>JSON字符串 --&gt; {@link JSONTokener} --&gt; {@link JSONObject}</li> * JSONTokener
* <li>JSON字符串 --&gt; {@link JSONTokener} --&gt; {@link JSONArray}</li> * 字符串 -------------> JSONObject
* </ul> * 字符串 -------------> JSONArray
* 字符串 -------------> JSONPrimitive
* }</pre>
* *
* @author looly * @author looly
* @since 6.0.0 * @since 6.0.0
@ -50,6 +52,10 @@ public class JSONParser {
*/ */
private final JSONConfig config; private final JSONConfig config;
private final JSONTokener tokener; private final JSONTokener tokener;
/**
* 过滤器用于过滤或修改键值对返回null表示忽略此键值对返回非null表示修改后返回<br>
* entry中key在JSONObject中为name在JSONArray中为index
*/
private Predicate<MutableEntry<Object, Object>> predicate; private Predicate<MutableEntry<Object, Object>> predicate;
/** /**
@ -73,18 +79,14 @@ public class JSONParser {
} }
/** /**
* 获取下一个值可以是 * 设置过滤器用于过滤或修改键值对返回null表示忽略此键值对返回非null表示修改后返回
* <pre>
* JSONObject
* JSONArray
* JSONPrimitive
* null
* </pre>
* *
* @return JSON值 * @param predicate 过滤器用于过滤或修改键值对返回null表示忽略此键值对返回非null表示修改后返回
* @return this
*/ */
public JSON nextValue() { public JSONParser setPredicate(final Predicate<MutableEntry<Object, Object>> predicate) {
return nextValue(tokener.nextClean()); this.predicate = predicate;
return this;
} }
/** /**
@ -98,34 +100,80 @@ public class JSONParser {
* *
* @return JSON值 * @return JSON值
*/ */
private JSON nextValue(final char c) { public JSON parse() {
switch (c) { return nextJSON(tokener.nextClean());
}
/**
* 解析为JSONObject或JSONArray解析值包括
* <pre>
* JSONObject
* JSONArray
* </pre>
*
* @param json JSON对象或数组用于存储解析结果
*/
public void parseTo(final JSON json) {
if(null == json){
return;
}
switch (tokener.nextClean()) {
case CharUtil.DELIM_START: case CharUtil.DELIM_START:
final JSONObject jsonObject = new JSONObject(tokener, config); nextTo((JSONObject) json);
nextJSONObject(jsonObject); break;
return jsonObject;
case CharUtil.BRACKET_START: case CharUtil.BRACKET_START:
final JSONArray jsonArray = new JSONArray(tokener, config); nextTo((JSONArray) json);
nextJSONArray(jsonArray); break;
return jsonArray;
default: default:
return nextJSONPrimitive(c); throw new JSONException("Unsupported: " + json.getClass());
} }
} }
/** /**
* 解析为JSONObject * 获取下一个值可以是
* <pre>
* JSONObject
* JSONArray
* JSONPrimitive
* null
* </pre>
*
* @return JSON值
*/
private JSON nextJSON(final char firstChar) {
final JSON result;
switch (firstChar) {
case CharUtil.DELIM_START:
final JSONObject jsonObject = new JSONObject(config);
nextTo(jsonObject);
result = jsonObject;
break;
case CharUtil.BRACKET_START:
final JSONArray jsonArray = new JSONArray(config);
nextTo(jsonArray);
result = jsonArray;
break;
default:
result = nextJSONPrimitive(firstChar);
}
return result;
}
/**
* 解析下一个值为JSONObject第一个字符必须读取完后再调用此方法
* *
* @param jsonObject JSON对象 * @param jsonObject JSON对象
*/ */
private void nextJSONObject(final JSONObject jsonObject) { private void nextTo(final JSONObject jsonObject) {
final JSONTokener tokener = this.tokener; final JSONTokener tokener = this.tokener;
char c; char c;
String key; String key;
for (; ; ) { for (; ; ) {
c = tokener.nextClean(); c = tokener.nextClean();
if (c == CharUtil.DELIM_END) {// 对象结束 if (c == CharUtil.DELIM_END) {
// 对象结束
return; return;
} else { } else {
key = tokener.nextKey(c); key = tokener.nextKey(c);
@ -135,7 +183,7 @@ public class JSONParser {
tokener.nextColon(); tokener.nextColon();
// 过滤并设置键值对 // 过滤并设置键值对
Object value = nextValue(); Object value = parse();
// 添加前置过滤通过MutablePair实现过滤修改键值对等 // 添加前置过滤通过MutablePair实现过滤修改键值对等
if (null != predicate) { if (null != predicate) {
final MutableEntry<Object, Object> pair = new MutableEntry<>(key, value); final MutableEntry<Object, Object> pair = new MutableEntry<>(key, value);
@ -169,31 +217,30 @@ public class JSONParser {
} }
/** /**
* 解析为JSONArray * 解析下一个值为JSONArray第一个字符必须读取完后再调用此方法
* *
* @param jsonArray JSON数组 * @param jsonArray JSON数组
*/ */
private void nextJSONArray(final JSONArray jsonArray) { private void nextTo(final JSONArray jsonArray) {
final JSONTokener tokener = this.tokener; final JSONTokener tokener = this.tokener;
char c; char c;
for (; ; ) { for (; ; ) {
c = tokener.nextClean(); c = tokener.nextClean();
switch (c) { if (c == CharUtil.BRACKET_END) {
case CharUtil.BRACKET_END: // 数组结束
return; return;
case CharUtil.COMMA: } else {
jsonArray.add(nextValue()); // ,value or value
default: Object value = nextJSON(CharUtil.COMMA == c ? tokener.nextClean() : c);
Object value = CharUtil.COMMA == c ? nextValue() : nextValue(c);
if (null != predicate) { if (null != predicate) {
// 使用过滤器 // 使用过滤器
final MutableEntry<Object, Object> pair = MutableEntry.of(jsonArray.size(), value); final MutableEntry<Object, Object> entry = MutableEntry.of(jsonArray.size(), value);
if (predicate.test(pair)) { if (predicate.test(entry)) {
// 使用修改后的键值对 // 使用修改后的键值对
value = pair.getValue(); value = entry.getValue();
jsonArray.add(value); jsonArray.add(value);
} }
}else { } else {
jsonArray.add(value); jsonArray.add(value);
} }
} }
@ -208,17 +255,17 @@ public class JSONParser {
* string * string
* </pre> * </pre>
* *
* @param c 值类型 * @param firstChar 第一个字符引号或字母
* @return JSONPrimitive或{@code null} * @return JSONPrimitive或{@code null}
*/ */
private JSONPrimitive nextJSONPrimitive(final char c) { private JSONPrimitive nextJSONPrimitive(final char firstChar) {
switch (c) { switch (firstChar) {
case CharUtil.DOUBLE_QUOTES: case CharUtil.DOUBLE_QUOTES:
case CharUtil.SINGLE_QUOTE: case CharUtil.SINGLE_QUOTE:
// 引号包围表示字符串值 // 引号包围表示字符串值
return new JSONPrimitive(tokener.nextWrapString(c)); return new JSONPrimitive(tokener.nextWrapString(firstChar));
default: default:
final Object value = InternalJSONUtil.parseValueFromString(tokener.nextUnwrapString(c)); final Object value = InternalJSONUtil.parseValueFromString(tokener.nextUnwrapString(firstChar));
// 非引号包围可能为boolean数字null等 // 非引号包围可能为boolean数字null等
return null == value ? null : new JSONPrimitive(value); return null == value ? null : new JSONPrimitive(value);
} }

View File

@ -128,6 +128,16 @@ public class JSONTokener extends ReaderWrapper {
return this.eof && !this.usePrevious; return this.eof && !this.usePrevious;
} }
/**
* 检查是否到了结尾<br>
* 如果读取完毕后还有未读的字符报错
*/
public void checkEnd(){
if(EOF != nextClean()){
throw syntaxError("Unread data");
}
}
/** /**
* 源字符串是否有更多的字符 * 源字符串是否有更多的字符
* *
@ -244,7 +254,7 @@ public class JSONTokener extends ReaderWrapper {
char c; char c;
while (true) { while (true) {
c = this.next(); c = this.next();
if (c == EOF || c > ' ') { if (c == EOF || c > CharUtil.SPACE) {
return c; return c;
} }
} }
@ -258,14 +268,13 @@ public class JSONTokener extends ReaderWrapper {
* @throws JSONException 非引号包裹的字符串 * @throws JSONException 非引号包裹的字符串
*/ */
public String nextKey(final char c) throws JSONException { public String nextKey(final char c) throws JSONException {
final char prev = this.previous;
switch (c) { switch (c) {
case JSONTokener.EOF: case JSONTokener.EOF:
// 未关闭对象 // 未关闭对象
throw syntaxError("A JSONObject text must end with '}'"); throw syntaxError("A JSONObject text must end with '}'");
case CharUtil.DELIM_START: case CharUtil.DELIM_START:
case CharUtil.BRACKET_END: case CharUtil.BRACKET_START:
if (prev == CharUtil.DELIM_START) { if (CharUtil.DELIM_START == this.previous) {
// 不允许嵌套对象{{}}{[]} // 不允许嵌套对象{{}}{[]}
throw syntaxError("A JSONObject can not directly nest another JSONObject or JSONArray."); throw syntaxError("A JSONObject can not directly nest another JSONObject or JSONArray.");
} }

View File

@ -124,7 +124,7 @@ public class OldJSONParser {
throw tokener.syntaxError("Expected a ':' after a key"); throw tokener.syntaxError("Expected a ':' after a key");
} }
jsonObject.set(key, nextValue(), predicate); jsonObject.set(key, nextValue(), null);
// Pairs are separated by ','. // Pairs are separated by ','.

View File

@ -32,5 +32,5 @@ public interface MatcherJSONSerializer<V> extends JSONSerializer<V> {
* @param context JSON上下文 * @param context JSON上下文
* @return 是否匹配 * @return 是否匹配
*/ */
boolean match(V bean, JSONContext context); boolean match(Object bean, JSONContext context);
} }

View File

@ -44,9 +44,8 @@ public class TimeZoneSerializer implements MatcherJSONSerializer<TimeZone>, Matc
return TimeZone.class.isAssignableFrom(TypeUtil.getClass(deserializeType)); return TimeZone.class.isAssignableFrom(TypeUtil.getClass(deserializeType));
} }
@SuppressWarnings("DataFlowIssue")
@Override @Override
public boolean match(final TimeZone bean, final JSONContext context) { public boolean match(final Object bean, final JSONContext context) {
return bean instanceof TimeZone; return bean instanceof TimeZone;
} }

View File

@ -41,12 +41,12 @@ public class JSONXMLParser {
* @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@link Predicate#test(Object)}{@code true}保留 * @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@link Predicate#test(Object)}{@code true}保留
* @return JSONXMLParser * @return JSONXMLParser
*/ */
public static JSONXMLParser of(final ParseConfig parseConfig, final Predicate<MutableEntry<String, Object>> predicate) { public static JSONXMLParser of(final ParseConfig parseConfig, final Predicate<MutableEntry<Object, Object>> predicate) {
return new JSONXMLParser(parseConfig, predicate); return new JSONXMLParser(parseConfig, predicate);
} }
private final ParseConfig parseConfig; private final ParseConfig parseConfig;
private final Predicate<MutableEntry<String, Object>> predicate; private final Predicate<MutableEntry<Object, Object>> predicate;
/** /**
* 构造 * 构造
@ -54,7 +54,7 @@ public class JSONXMLParser {
* @param parseConfig 解析选项 * @param parseConfig 解析选项
* @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@link Predicate#test(Object)}{@code true}保留 * @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@link Predicate#test(Object)}{@code true}保留
*/ */
public JSONXMLParser(final ParseConfig parseConfig, final Predicate<MutableEntry<String, Object>> predicate) { public JSONXMLParser(final ParseConfig parseConfig, final Predicate<MutableEntry<Object, Object>> predicate) {
this.parseConfig = parseConfig; this.parseConfig = parseConfig;
this.predicate = predicate; this.predicate = predicate;
} }

View File

@ -27,7 +27,7 @@ public class IssueI9DX5HTest {
void xmlToJSONTest() { void xmlToJSONTest() {
final String xml = "<GoodMsg>你好</GoodMsg>"; final String xml = "<GoodMsg>你好</GoodMsg>";
final JSONObject jsonObject = new JSONObject(xml, JSONConfig.of(), entry -> { final JSONObject jsonObject = new JSONObject(xml, JSONConfig.of(), entry -> {
entry.setKey(StrUtil.toUnderlineCase(entry.getKey())); entry.setKey(StrUtil.toUnderlineCase((CharSequence) entry.getKey()));
return true; return true;
}); });

View File

@ -29,10 +29,7 @@ import org.dromara.hutool.json.test.bean.KeyBean;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
@ -322,7 +319,7 @@ public class JSONArrayTest {
if ("111".equals(o.getStr("id"))) { if ("111".equals(o.getStr("id"))) {
o.set("name", "test1_edit"); o.set("name", "test1_edit");
} }
mutable.set(o); mutable.set(new AbstractMap.SimpleEntry<>(1, o));
return true; return true;
}); });
assertEquals(2, array.size()); assertEquals(2, array.size());

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.hutool.json.reader;
import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.JSONConfig;
import org.dromara.hutool.json.JSONObject;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class JSONParserTest {
@Test
void parseTest() {
final String jsonStr = " {\"a\": 1} ";
final JSONParser jsonParser = JSONParser.of(new JSONTokener(jsonStr), JSONConfig.of());
final JSON parse = jsonParser.parse();
Assertions.assertEquals("{\"a\":1}", parse.toString());
}
@Test
void nextToTest() {
final String jsonStr = "{\"a\": 1}";
JSONParser.of(new JSONTokener(jsonStr), JSONConfig.of()).parseTo(new JSONObject());
}
}