From 1f705e0e1f50cc06edc3391baf19bfd0fc0656db Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 13 Sep 2024 00:55:35 +0800 Subject: [PATCH] add JSONParser --- .../dromara/hutool/json/InternalJSONUtil.java | 2 +- .../org/dromara/hutool/json/JSONArray.java | 8 +- .../org/dromara/hutool/json/JSONObject.java | 29 ++-- .../dromara/hutool/json/JSONPrimitive.java | 6 + .../hutool/json/convert/JSONConverter.java | 14 +- .../hutool/json/mapper/JSONArrayMapper.java | 28 ++-- .../hutool/json/mapper/JSONObjectMapper.java | 16 +- .../hutool/json/reader/JSONParser.java | 147 ++++++++++++------ .../hutool/json/reader/JSONTokener.java | 17 +- .../hutool/json/reader/OldJSONParser.java | 2 +- .../serializer/MatcherJSONSerializer.java | 2 +- .../serializer/impl/TimeZoneSerializer.java | 3 +- .../hutool/json/xml/JSONXMLParser.java | 6 +- .../dromara/hutool/json/IssueI9DX5HTest.java | 2 +- .../dromara/hutool/json/JSONArrayTest.java | 7 +- .../hutool/json/reader/JSONParserTest.java | 39 +++++ 16 files changed, 219 insertions(+), 109 deletions(-) create mode 100644 hutool-json/src/test/java/org/dromara/hutool/json/reader/JSONParserTest.java diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/InternalJSONUtil.java b/hutool-json/src/main/java/org/dromara/hutool/json/InternalJSONUtil.java index e3ac8398d..d0502e45a 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/InternalJSONUtil.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/InternalJSONUtil.java @@ -143,7 +143,7 @@ public final class InternalJSONUtil { * @param value 值 * @param predicate 属性过滤器,{@link Predicate#test(Object)}为{@code true}保留 */ - public static void propertyPut(final JSONObject jsonObject, final Object key, final Object value, final Predicate> predicate) { + public static void propertyPut(final JSONObject jsonObject, final Object key, final Object value, final Predicate> predicate) { final String[] path = SplitUtil.splitToArray(ConvertUtil.toStr(key), StrUtil.DOT); final int last = path.length - 1; JSONObject target = jsonObject; diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/JSONArray.java b/hutool-json/src/main/java/org/dromara/hutool/json/JSONArray.java index b32e117cc..eecbdacc7 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/JSONArray.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/JSONArray.java @@ -164,7 +164,7 @@ public class JSONArray implements JSON, JSONGetter, List, Rando * @throws JSONException 非数组或集合 * @since 5.8.0 */ - public JSONArray(final Object object, final JSONConfig jsonConfig, final Predicate> predicate) throws JSONException { + public JSONArray(final Object object, final JSONConfig jsonConfig, final Predicate> predicate) throws JSONException { this(DEFAULT_CAPACITY, jsonConfig); JSONArrayMapper.of(object, predicate).mapTo(this); } @@ -201,7 +201,11 @@ public class JSONArray implements JSON, JSONGetter, List, Rando @Override 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 diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/JSONObject.java b/hutool-json/src/main/java/org/dromara/hutool/json/JSONObject.java index 9bc47aae2..52ed0e9c1 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/JSONObject.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/JSONObject.java @@ -152,7 +152,7 @@ public class JSONObject extends MapWrapper implements JSON, JSON * @param predicate 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@code null}表示不过滤,{@link Predicate#test(Object)}为{@code true}保留 * @since 5.8.0 */ - public JSONObject(final Object source, final JSONConfig config, final Predicate> predicate) { + public JSONObject(final Object source, final JSONConfig config, final Predicate> predicate) { this(DEFAULT_CAPACITY, config); JSONObjectMapper.of(source, predicate).mapTo(this); } @@ -200,7 +200,16 @@ public class JSONObject extends MapWrapper implements JSON, JSON @Override 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 implements JSON, JSON * @throws JSONException 值是无穷数字、键重复抛出异常 * @since 5.8.0 */ - public JSONObject set(final String key, final Object value, final Predicate> predicate) throws JSONException { + public JSONObject set(final String key, final Object value, final Predicate> predicate) throws JSONException { put(key, value, predicate, config().isCheckDuplicate()); return this; } @@ -284,7 +293,7 @@ public class JSONObject extends MapWrapper implements JSON, JSON * @throws JSONException 值是无穷数字抛出此异常 * @since 5.8.0 */ - public JSONObject set(final String key, final Object value, final Predicate> predicate, final boolean checkDuplicate) throws JSONException { + public JSONObject set(final String key, final Object value, final Predicate> predicate, final boolean checkDuplicate) throws JSONException { put(key, value, predicate, checkDuplicate); return this; } @@ -343,13 +352,13 @@ public class JSONObject extends MapWrapper implements JSON, JSON * @throws JSONException 如果给定键为{@code null}或者键对应的值存在且为非JSONArray * @since 6.0.0 */ - public JSONObject append(String key, Object value, final Predicate> predicate) throws JSONException { + public JSONObject append(String key, Object value, final Predicate> predicate) throws JSONException { // 添加前置过滤,通过MutablePair实现过滤、修改键值对等 if (null != predicate) { - final MutableEntry pair = new MutableEntry<>(key, value); + final MutableEntry pair = new MutableEntry<>(key, value); if (predicate.test(pair)) { // 使用修改后的键值对 - key = pair.getKey(); + key = (String) pair.getKey(); value = pair.getValue(); } else { // 键值对被过滤 @@ -465,17 +474,17 @@ public class JSONObject extends MapWrapper implements JSON, JSON * @throws JSONException 值是无穷数字抛出此异常 * @since 5.8.0 */ - private Object put(String key, Object value, final Predicate> predicate, final boolean checkDuplicate) throws JSONException { + private Object put(String key, Object value, final Predicate> predicate, final boolean checkDuplicate) throws JSONException { if (null == key) { return null; } // 添加前置过滤,通过MutablePair实现过滤、修改键值对等 if (null != predicate) { - final MutableEntry pair = new MutableEntry<>(key, value); + final MutableEntry pair = new MutableEntry<>(key, value); if (predicate.test(pair)) { // 使用修改后的键值对 - key = pair.getKey(); + key = (String) pair.getKey(); value = pair.getValue(); } else { // 键值对被过滤 diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/JSONPrimitive.java b/hutool-json/src/main/java/org/dromara/hutool/json/JSONPrimitive.java index d48ac7a1c..7338f0dff 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/JSONPrimitive.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/JSONPrimitive.java @@ -24,6 +24,7 @@ import org.dromara.hutool.json.writer.JSONWriter; import java.io.StringWriter; import java.io.Writer; +import java.lang.reflect.Type; import java.util.function.Predicate; /** @@ -107,6 +108,11 @@ public class JSONPrimitive implements JSON { return 1; } + @Override + public T convert(final Type targetType, final Object value, final T defaultValue) { + return JSON.super.convert(targetType, this.value, defaultValue); + } + @Override public Writer write(final Writer writer, final int indentFactor, final int indent, final Predicate> predicate) throws JSONException { final Object value = this.value; diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java b/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java index a4de6ec5f..69840953c 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java @@ -30,7 +30,7 @@ import org.dromara.hutool.core.reflect.TypeUtil; import org.dromara.hutool.core.reflect.kotlin.KClassUtil; import org.dromara.hutool.core.text.StrUtil; 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.serializer.*; @@ -202,16 +202,8 @@ public class JSONConverter implements Converter, Serializable { } // RFC8259,JSON字符串值、number, boolean, or null - final OldJSONParser jsonParser = OldJSONParser.of(new JSONTokener(jsonStr), config); - final Object value = jsonParser.nextValue(); - 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); + final JSONParser jsonParser = JSONParser.of(new JSONTokener(jsonStr), config); + return jsonParser.parse(); } // ----------------------------------------------------------- Private method start diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONArrayMapper.java b/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONArrayMapper.java index 300aaee4b..35a0ec58c 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONArrayMapper.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONArrayMapper.java @@ -19,12 +19,12 @@ package org.dromara.hutool.json.mapper; import org.dromara.hutool.core.array.ArrayUtil; import org.dromara.hutool.core.collection.iter.ArrayIter; 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.json.JSONArray; import org.dromara.hutool.json.JSONConfig; 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.serializer.JSONSerializer; import org.dromara.hutool.json.serializer.SerializerManager; @@ -58,12 +58,12 @@ public class JSONArrayMapper { * @param predicate 值过滤编辑器,可以通过实现此接口,完成解析前对值的过滤和修改操作,{@code null}表示不过滤,,{@link Predicate#test(Object)}为{@code true}保留 * @return ObjectMapper */ - public static JSONArrayMapper of(final Object source, final Predicate> predicate) { + public static JSONArrayMapper of(final Object source, final Predicate> predicate) { return new JSONArrayMapper(source, predicate); } private final Object source; - private final Predicate> predicate; + private final Predicate> predicate; /** * 构造 @@ -71,7 +71,7 @@ public class JSONArrayMapper { * @param source 来源对象 * @param predicate 值过滤编辑器,可以通过实现此接口,完成解析前对值的过滤和修改操作,{@code null}表示不过滤,,{@link Predicate#test(Object)}为{@code true}保留 */ - public JSONArrayMapper(final Object source, final Predicate> predicate) { + public JSONArrayMapper(final Object source, final Predicate> predicate) { this.source = source; this.predicate = predicate; } @@ -82,7 +82,6 @@ public class JSONArrayMapper { * @param jsonArray 目标{@link JSONArray} * @throws JSONException 非数组或集合 */ - @SuppressWarnings("unchecked") public void mapTo(final JSONArray jsonArray) throws JSONException { final Object source = this.source; if (null == source) { @@ -98,8 +97,8 @@ public class JSONArrayMapper { if (source instanceof JSONTokener) { mapFromTokener((JSONTokener) source, JSONConfig.of(), jsonArray); - }if (source instanceof OldJSONParser) { - ((OldJSONParser)source).parseTo(jsonArray, this.predicate); + }if (source instanceof JSONParser) { + ((JSONParser)source).parseTo(jsonArray); } else if (source instanceof CharSequence) { // JSON字符串 mapFromStr((CharSequence) source, jsonArray); @@ -139,7 +138,16 @@ public class JSONArrayMapper { next = iter.next(); // 检查循环引用 if (next != source) { - jsonArray.add(next, predicate); + if(null != this.predicate){ + final MutableEntry 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} */ 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); } } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONObjectMapper.java b/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONObjectMapper.java index ad7e32146..d4e75107e 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONObjectMapper.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONObjectMapper.java @@ -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.text.StrUtil; 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.serializer.JSONSerializer; import org.dromara.hutool.json.serializer.SerializerManager; @@ -66,12 +66,12 @@ public class JSONObjectMapper { * @param predicate 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@link Predicate#test(Object)}为{@code true}保留 * @return ObjectMapper */ - public static JSONObjectMapper of(final Object source, final Predicate> predicate) { + public static JSONObjectMapper of(final Object source, final Predicate> predicate) { return new JSONObjectMapper(source, predicate); } private final Object source; - private final Predicate> predicate; + private final Predicate> predicate; /** * 构造 @@ -79,7 +79,7 @@ public class JSONObjectMapper { * @param source 来源对象 * @param predicate 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@link Predicate#test(Object)}为{@code true}保留 */ - public JSONObjectMapper(final Object source, final Predicate> predicate) { + public JSONObjectMapper(final Object source, final Predicate> predicate) { this.source = source; this.predicate = predicate; } @@ -111,9 +111,9 @@ public class JSONObjectMapper { if (source instanceof JSONTokener) { // JSONTokener mapFromTokener((JSONTokener) source, jsonObject.config(), jsonObject); - }if (source instanceof OldJSONParser) { + }if (source instanceof JSONParser) { // JSONParser - ((OldJSONParser) source).parseTo(jsonObject, this.predicate); + ((JSONParser) source).parseTo(jsonObject); } else if (source instanceof Map) { // Map for (final Map.Entry e : ((Map) source).entrySet()) { @@ -180,7 +180,7 @@ public class JSONObjectMapper { JSONXMLParser.of(ParseConfig.of(), this.predicate).parseJSONObject(jsonStr, jsonObject); 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} */ 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); } /** diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/reader/JSONParser.java b/hutool-json/src/main/java/org/dromara/hutool/json/reader/JSONParser.java index 95eedb5f0..241af4a24 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/reader/JSONParser.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/reader/JSONParser.java @@ -24,10 +24,12 @@ import java.util.function.Predicate; /** * JSON字符串解析器,实现: - *
    - *
  • JSON字符串 --> {@link JSONTokener} --> {@link JSONObject}
  • - *
  • JSON字符串 --> {@link JSONTokener} --> {@link JSONArray}
  • - *
+ *
{@code
+ *            JSONTokener
+ *     字符串 -------------> JSONObject
+ *     字符串 -------------> JSONArray
+ *     字符串 -------------> JSONPrimitive
+ * }
* * @author looly * @since 6.0.0 @@ -50,6 +52,10 @@ public class JSONParser { */ private final JSONConfig config; private final JSONTokener tokener; + /** + * 过滤器,用于过滤或修改键值对,返回null表示忽略此键值对,返回非null表示修改后返回
+ * entry中,key在JSONObject中为name,在JSONArray中为index + */ private Predicate> predicate; /** @@ -73,18 +79,14 @@ public class JSONParser { } /** - * 获取下一个值,可以是: - *
-	 *     JSONObject
-	 *     JSONArray
-	 *     JSONPrimitive
-	 *     null
-	 * 
+ * 设置过滤器,用于过滤或修改键值对,返回null表示忽略此键值对,返回非null表示修改后返回 * - * @return JSON值 + * @param predicate 过滤器,用于过滤或修改键值对,返回null表示忽略此键值对,返回非null表示修改后返回 + * @return this */ - public JSON nextValue() { - return nextValue(tokener.nextClean()); + public JSONParser setPredicate(final Predicate> predicate) { + this.predicate = predicate; + return this; } /** @@ -98,34 +100,80 @@ public class JSONParser { * * @return JSON值 */ - private JSON nextValue(final char c) { - switch (c) { + public JSON parse() { + return nextJSON(tokener.nextClean()); + } + + /** + * 解析为JSONObject或JSONArray,解析值包括: + *
+	 *     JSONObject
+	 *     JSONArray
+	 * 
+ * + * @param json JSON对象或数组,用于存储解析结果 + */ + public void parseTo(final JSON json) { + if(null == json){ + return; + } + switch (tokener.nextClean()) { case CharUtil.DELIM_START: - final JSONObject jsonObject = new JSONObject(tokener, config); - nextJSONObject(jsonObject); - return jsonObject; + nextTo((JSONObject) json); + break; case CharUtil.BRACKET_START: - final JSONArray jsonArray = new JSONArray(tokener, config); - nextJSONArray(jsonArray); - return jsonArray; + nextTo((JSONArray) json); + break; default: - return nextJSONPrimitive(c); + throw new JSONException("Unsupported: " + json.getClass()); } } /** - * 解析为JSONObject + * 获取下一个值,可以是: + *
+	 *     JSONObject
+	 *     JSONArray
+	 *     JSONPrimitive
+	 *     null
+	 * 
+ * + * @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对象 */ - private void nextJSONObject(final JSONObject jsonObject) { + private void nextTo(final JSONObject jsonObject) { final JSONTokener tokener = this.tokener; char c; String key; for (; ; ) { c = tokener.nextClean(); - if (c == CharUtil.DELIM_END) {// 对象结束 + if (c == CharUtil.DELIM_END) { + // 对象结束 return; } else { key = tokener.nextKey(c); @@ -135,7 +183,7 @@ public class JSONParser { tokener.nextColon(); // 过滤并设置键值对 - Object value = nextValue(); + Object value = parse(); // 添加前置过滤,通过MutablePair实现过滤、修改键值对等 if (null != predicate) { final MutableEntry pair = new MutableEntry<>(key, value); @@ -169,33 +217,32 @@ public class JSONParser { } /** - * 解析为JSONArray + * 解析下一个值为JSONArray,第一个字符必须读取完后再调用此方法 * * @param jsonArray JSON数组 */ - private void nextJSONArray(final JSONArray jsonArray) { + private void nextTo(final JSONArray jsonArray) { final JSONTokener tokener = this.tokener; char c; for (; ; ) { c = tokener.nextClean(); - switch (c) { - case CharUtil.BRACKET_END: - return; - case CharUtil.COMMA: - jsonArray.add(nextValue()); - default: - Object value = CharUtil.COMMA == c ? nextValue() : nextValue(c); - if (null != predicate) { - // 使用过滤器 - final MutableEntry pair = MutableEntry.of(jsonArray.size(), value); - if (predicate.test(pair)) { - // 使用修改后的键值对 - value = pair.getValue(); - jsonArray.add(value); - } - }else { + if (c == CharUtil.BRACKET_END) { + // 数组结束 + return; + } else { + // ,value or value + Object value = nextJSON(CharUtil.COMMA == c ? tokener.nextClean() : c); + if (null != predicate) { + // 使用过滤器 + final MutableEntry entry = MutableEntry.of(jsonArray.size(), value); + if (predicate.test(entry)) { + // 使用修改后的键值对 + value = entry.getValue(); jsonArray.add(value); } + } else { + jsonArray.add(value); + } } } } @@ -208,17 +255,17 @@ public class JSONParser { * string * * - * @param c 值类型 + * @param firstChar 第一个字符,引号或字母 * @return JSONPrimitive或{@code null} */ - private JSONPrimitive nextJSONPrimitive(final char c) { - switch (c) { + private JSONPrimitive nextJSONPrimitive(final char firstChar) { + switch (firstChar) { case CharUtil.DOUBLE_QUOTES: case CharUtil.SINGLE_QUOTE: // 引号包围,表示字符串值 - return new JSONPrimitive(tokener.nextWrapString(c)); + return new JSONPrimitive(tokener.nextWrapString(firstChar)); default: - final Object value = InternalJSONUtil.parseValueFromString(tokener.nextUnwrapString(c)); + final Object value = InternalJSONUtil.parseValueFromString(tokener.nextUnwrapString(firstChar)); // 非引号包围,可能为boolean、数字、null等 return null == value ? null : new JSONPrimitive(value); } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/reader/JSONTokener.java b/hutool-json/src/main/java/org/dromara/hutool/json/reader/JSONTokener.java index 96ea999e4..26f419a67 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/reader/JSONTokener.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/reader/JSONTokener.java @@ -128,6 +128,16 @@ public class JSONTokener extends ReaderWrapper { return this.eof && !this.usePrevious; } + /** + * 检查是否到了结尾
+ * 如果读取完毕后还有未读的字符,报错 + */ + public void checkEnd(){ + if(EOF != nextClean()){ + throw syntaxError("Unread data"); + } + } + /** * 源字符串是否有更多的字符 * @@ -244,7 +254,7 @@ public class JSONTokener extends ReaderWrapper { char c; while (true) { c = this.next(); - if (c == EOF || c > ' ') { + if (c == EOF || c > CharUtil.SPACE) { return c; } } @@ -258,14 +268,13 @@ public class JSONTokener extends ReaderWrapper { * @throws JSONException 非引号包裹的字符串 */ public String nextKey(final char c) throws JSONException { - final char prev = this.previous; switch (c) { case JSONTokener.EOF: // 未关闭对象 throw syntaxError("A JSONObject text must end with '}'"); case CharUtil.DELIM_START: - case CharUtil.BRACKET_END: - if (prev == CharUtil.DELIM_START) { + case CharUtil.BRACKET_START: + if (CharUtil.DELIM_START == this.previous) { // 不允许嵌套对象,如{{}}或{[]} throw syntaxError("A JSONObject can not directly nest another JSONObject or JSONArray."); } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/reader/OldJSONParser.java b/hutool-json/src/main/java/org/dromara/hutool/json/reader/OldJSONParser.java index c98d118eb..410446f89 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/reader/OldJSONParser.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/reader/OldJSONParser.java @@ -124,7 +124,7 @@ public class OldJSONParser { throw tokener.syntaxError("Expected a ':' after a key"); } - jsonObject.set(key, nextValue(), predicate); + jsonObject.set(key, nextValue(), null); // Pairs are separated by ','. diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/MatcherJSONSerializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/MatcherJSONSerializer.java index cc735353a..3ede9fa8f 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/MatcherJSONSerializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/MatcherJSONSerializer.java @@ -32,5 +32,5 @@ public interface MatcherJSONSerializer extends JSONSerializer { * @param context JSON上下文 * @return 是否匹配 */ - boolean match(V bean, JSONContext context); + boolean match(Object bean, JSONContext context); } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/TimeZoneSerializer.java b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/TimeZoneSerializer.java index 4e22d6387..b86b682c7 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/TimeZoneSerializer.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/serializer/impl/TimeZoneSerializer.java @@ -44,9 +44,8 @@ public class TimeZoneSerializer implements MatcherJSONSerializer, Matc return TimeZone.class.isAssignableFrom(TypeUtil.getClass(deserializeType)); } - @SuppressWarnings("DataFlowIssue") @Override - public boolean match(final TimeZone bean, final JSONContext context) { + public boolean match(final Object bean, final JSONContext context) { return bean instanceof TimeZone; } diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLParser.java b/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLParser.java index cc25314e4..f79ed3a41 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLParser.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLParser.java @@ -41,12 +41,12 @@ public class JSONXMLParser { * @param predicate 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@link Predicate#test(Object)}为{@code true}保留 * @return JSONXMLParser */ - public static JSONXMLParser of(final ParseConfig parseConfig, final Predicate> predicate) { + public static JSONXMLParser of(final ParseConfig parseConfig, final Predicate> predicate) { return new JSONXMLParser(parseConfig, predicate); } private final ParseConfig parseConfig; - private final Predicate> predicate; + private final Predicate> predicate; /** * 构造 @@ -54,7 +54,7 @@ public class JSONXMLParser { * @param parseConfig 解析选项 * @param predicate 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@link Predicate#test(Object)}为{@code true}保留 */ - public JSONXMLParser(final ParseConfig parseConfig, final Predicate> predicate) { + public JSONXMLParser(final ParseConfig parseConfig, final Predicate> predicate) { this.parseConfig = parseConfig; this.predicate = predicate; } diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/IssueI9DX5HTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/IssueI9DX5HTest.java index 1b95c30dc..b0d7cf01f 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/IssueI9DX5HTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/IssueI9DX5HTest.java @@ -27,7 +27,7 @@ public class IssueI9DX5HTest { void xmlToJSONTest() { final String xml = "你好"; final JSONObject jsonObject = new JSONObject(xml, JSONConfig.of(), entry -> { - entry.setKey(StrUtil.toUnderlineCase(entry.getKey())); + entry.setKey(StrUtil.toUnderlineCase((CharSequence) entry.getKey())); return true; }); diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/JSONArrayTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/JSONArrayTest.java index 226a2cc64..827f3e3b0 100644 --- a/hutool-json/src/test/java/org/dromara/hutool/json/JSONArrayTest.java +++ b/hutool-json/src/test/java/org/dromara/hutool/json/JSONArrayTest.java @@ -29,10 +29,7 @@ import org.dromara.hutool.json.test.bean.KeyBean; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -322,7 +319,7 @@ public class JSONArrayTest { if ("111".equals(o.getStr("id"))) { o.set("name", "test1_edit"); } - mutable.set(o); + mutable.set(new AbstractMap.SimpleEntry<>(1, o)); return true; }); assertEquals(2, array.size()); diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/reader/JSONParserTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/reader/JSONParserTest.java new file mode 100644 index 000000000..a96a96e07 --- /dev/null +++ b/hutool-json/src/test/java/org/dromara/hutool/json/reader/JSONParserTest.java @@ -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()); + } +}