diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/JSON.java b/hutool-json/src/main/java/org/dromara/hutool/json/JSON.java index 71cd5eda9..cff762d8e 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/JSON.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/JSON.java @@ -29,7 +29,13 @@ import java.lang.reflect.Type; import java.util.function.Predicate; /** - * JSON接口 + * JSON树模型接口,表示树中的一个节点。实现包括: + * * * @author Looly */ 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 1e8dc9f9e..a4de6ec5f 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.JSONParser; +import org.dromara.hutool.json.reader.OldJSONParser; import org.dromara.hutool.json.reader.JSONTokener; import org.dromara.hutool.json.serializer.*; @@ -202,7 +202,7 @@ public class JSONConverter implements Converter, Serializable { } // RFC8259,JSON字符串值、number, boolean, or null - final JSONParser jsonParser = JSONParser.of(new JSONTokener(jsonStr), config); + final OldJSONParser jsonParser = OldJSONParser.of(new JSONTokener(jsonStr), config); final Object value = jsonParser.nextValue(); if (jsonParser.getTokener().nextClean() != JSONTokener.EOF) { // 对于用户提供的未转义字符串导致解析未结束,报错 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 85421f271..300aaee4b 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 @@ -24,7 +24,7 @@ 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.JSONParser; +import org.dromara.hutool.json.reader.OldJSONParser; import org.dromara.hutool.json.reader.JSONTokener; import org.dromara.hutool.json.serializer.JSONSerializer; import org.dromara.hutool.json.serializer.SerializerManager; @@ -98,8 +98,8 @@ public class JSONArrayMapper { if (source instanceof JSONTokener) { mapFromTokener((JSONTokener) source, JSONConfig.of(), jsonArray); - }if (source instanceof JSONParser) { - ((JSONParser)source).parseTo(jsonArray, this.predicate); + }if (source instanceof OldJSONParser) { + ((OldJSONParser)source).parseTo(jsonArray, this.predicate); } else if (source instanceof CharSequence) { // JSON字符串 mapFromStr((CharSequence) source, jsonArray); @@ -164,6 +164,6 @@ public class JSONArrayMapper { * @param jsonArray {@link JSONArray} */ private void mapFromTokener(final JSONTokener x, final JSONConfig config, final JSONArray jsonArray) { - JSONParser.of(x, config).parseTo(jsonArray, this.predicate); + OldJSONParser.of(x, config).parseTo(jsonArray, this.predicate); } } 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 8733883f2..ad7e32146 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.JSONParser; +import org.dromara.hutool.json.reader.OldJSONParser; import org.dromara.hutool.json.reader.JSONTokener; import org.dromara.hutool.json.serializer.JSONSerializer; import org.dromara.hutool.json.serializer.SerializerManager; @@ -111,9 +111,9 @@ public class JSONObjectMapper { if (source instanceof JSONTokener) { // JSONTokener mapFromTokener((JSONTokener) source, jsonObject.config(), jsonObject); - }if (source instanceof JSONParser) { + }if (source instanceof OldJSONParser) { // JSONParser - ((JSONParser) source).parseTo(jsonObject, this.predicate); + ((OldJSONParser) source).parseTo(jsonObject, this.predicate); } else if (source instanceof Map) { // Map for (final Map.Entry e : ((Map) source).entrySet()) { @@ -191,7 +191,7 @@ public class JSONObjectMapper { * @param jsonObject {@link JSONObject} */ private void mapFromTokener(final JSONTokener x, final JSONConfig config, final JSONObject jsonObject) { - JSONParser.of(x, config).parseTo(jsonObject, this.predicate); + OldJSONParser.of(x, config).parseTo(jsonObject, this.predicate); } /** 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 cbbf3008c..95eedb5f0 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2024 Hutool Team and hutool.cn + * 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. @@ -16,7 +16,6 @@ package org.dromara.hutool.json.reader; -import org.dromara.hutool.core.lang.mutable.Mutable; import org.dromara.hutool.core.lang.mutable.MutableEntry; import org.dromara.hutool.core.text.CharUtil; import org.dromara.hutool.json.*; @@ -31,7 +30,7 @@ import java.util.function.Predicate; * * * @author looly - * @since 5.8.0 + * @since 6.0.0 */ public class JSONParser { @@ -51,6 +50,7 @@ public class JSONParser { */ private final JSONConfig config; private final JSONTokener tokener; + private Predicate> predicate; /** * 构造 @@ -73,72 +73,94 @@ public class JSONParser { } /** - * 是否结束 + * 获取下一个值,可以是: + *
+	 *     JSONObject
+	 *     JSONArray
+	 *     JSONPrimitive
+	 *     null
+	 * 
* - * @return 是否结束 + * @return JSON值 */ - public boolean end() { - return this.tokener.end(); + public JSON nextValue() { + return nextValue(tokener.nextClean()); } - // region parseTo + /** + * 获取下一个值,可以是: + *
+	 *     JSONObject
+	 *     JSONArray
+	 *     JSONPrimitive
+	 *     null
+	 * 
+ * + * @return JSON值 + */ + private JSON nextValue(final char c) { + switch (c) { + case CharUtil.DELIM_START: + final JSONObject jsonObject = new JSONObject(tokener, config); + nextJSONObject(jsonObject); + return jsonObject; + case CharUtil.BRACKET_START: + final JSONArray jsonArray = new JSONArray(tokener, config); + nextJSONArray(jsonArray); + return jsonArray; + default: + return nextJSONPrimitive(c); + } + } /** - * 解析{@link JSONTokener}中的字符到目标的{@link JSONObject}中 + * 解析为JSONObject * - * @param jsonObject {@link JSONObject} - * @param predicate 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@code null}表示不过滤,{@link Predicate#test(Object)}为{@code true}保留 + * @param jsonObject JSON对象 */ - public void parseTo(final JSONObject jsonObject, final Predicate> predicate) { + private void nextJSONObject(final JSONObject jsonObject) { final JSONTokener tokener = this.tokener; - if (tokener.nextClean() != '{') { - throw tokener.syntaxError("A JSONObject text must begin with '{'"); - } - - char prev; char c; String key; - while (true) { - prev = tokener.getPrevious(); + for (; ; ) { c = tokener.nextClean(); - switch (c) { - case 0: - throw tokener.syntaxError("A JSONObject text must end with '}'"); - case '}': - return; - case '{': - case '[': - if (prev == '{') { - throw tokener.syntaxError("A JSONObject can not directly nest another JSONObject or JSONArray."); - } - default: - tokener.back(); - key = tokener.nextString(); + if (c == CharUtil.DELIM_END) {// 对象结束 + return; + } else { + key = tokener.nextKey(c); } // The key is followed by ':'. + tokener.nextColon(); - c = tokener.nextClean(); - if (c != ':') { - throw tokener.syntaxError("Expected a ':' after a key"); + // 过滤并设置键值对 + Object value = nextValue(); + // 添加前置过滤,通过MutablePair实现过滤、修改键值对等 + if (null != predicate) { + final MutableEntry pair = new MutableEntry<>(key, value); + if (predicate.test(pair)) { + // 使用修改后的键值对 + key = (String) pair.getKey(); + value = pair.getValue(); + jsonObject.set(key, value); + } + }else { + jsonObject.set(key, value); } - jsonObject.set(key, nextValue(), predicate); - - // Pairs are separated by ','. - + // Pairs are separated by ',' or ';' switch (tokener.nextClean()) { case ';': case CharUtil.COMMA: - if (tokener.nextClean() == '}') { + if (tokener.nextClean() == CharUtil.DELIM_END) { // issue#2380 // 尾后逗号(Trailing Commas),JSON中虽然不支持,但是ECMAScript 2017支持,此处做兼容。 return; } tokener.back(); break; - case '}': + case CharUtil.DELIM_END: return; default: throw tokener.syntaxError("Expected a ',' or '}'"); @@ -147,111 +169,58 @@ public class JSONParser { } /** - * 解析JSON字符串到{@link JSONArray}中 + * 解析为JSONArray * - * @param jsonArray {@link JSONArray} - * @param predicate 键值对过滤编辑器,可以通过实现此接口,完成解析前对值的过滤和修改操作,{@code null} 表示不过滤,,{@link Predicate#test(Object)}为{@code true}保留 + * @param jsonArray JSON数组 */ - public void parseTo(final JSONArray jsonArray, final Predicate> predicate) { - final JSONTokener x = this.tokener; - - if (x.nextClean() != '[') { - throw x.syntaxError("A JSONArray text must start with '['"); - } - if (x.nextClean() != ']') { - x.back(); - for (; ; ) { - if (x.nextClean() == CharUtil.COMMA) { - x.back(); - jsonArray.add(null, predicate); - } else { - x.back(); - jsonArray.add(nextValue(), predicate); - } - switch (x.nextClean()) { - case CharUtil.COMMA: - if (x.nextClean() == ']') { - return; - } - x.back(); - break; - case ']': - return; - default: - throw x.syntaxError("Expected a ',' or ']'"); - } - } - } - } - // endregion - - /** - * 获得下一个值,值类型可以是Boolean, Double, Integer, JSONArray, JSONObject, Long, or String - * - * @return Boolean, Double, Integer, JSONArray, JSONObject, Long, or String - * @throws JSONException 语法错误 - */ - public Object nextValue() throws JSONException { - return nextValue((token, tokener, config) -> { - switch (token) { - case CharUtil.DELIM_START: - try { - return new JSONObject(this, config); - } catch (final StackOverflowError e) { - throw new JSONException("JSONObject depth too large to process.", e); - } - case CharUtil.BRACKET_START: - try { - return new JSONArray(this, config); - } catch (final StackOverflowError e) { - throw new JSONException("JSONObject depth too large to process.", e); - } - } - throw new JSONException("Unsupported object build for token {}", token); - }); - } - - /** - * 获得下一个值,值类型可以是Boolean, Double, Integer, JSONArray, JSONObject, Long, or String - * - * @param objectBuilder JSON对象构建器 - * @return Boolean, Double, Integer, JSONArray, JSONObject, Long, or String - * @throws JSONException 语法错误 - */ - public Object nextValue(final ObjectBuilder objectBuilder) throws JSONException { + private void nextJSONArray(final JSONArray jsonArray) { final JSONTokener tokener = this.tokener; - final char c = tokener.nextClean(); + 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 { + jsonArray.add(value); + } + } + } + } + + /** + * 解析为JSONPrimitive或{@code null},解析值包括: + *
+	 *     boolean
+	 *     number
+	 *     string
+	 * 
+ * + * @param c 值类型 + * @return JSONPrimitive或{@code null} + */ + private JSONPrimitive nextJSONPrimitive(final char c) { switch (c) { case CharUtil.DOUBLE_QUOTES: case CharUtil.SINGLE_QUOTE: - return tokener.nextString(c); - case CharUtil.DELIM_START: - case CharUtil.BRACKET_START: - tokener.back(); - return objectBuilder.build(c, tokener, this.config); + // 引号包围,表示字符串值 + return new JSONPrimitive(tokener.nextWrapString(c)); + default: + final Object value = InternalJSONUtil.parseValueFromString(tokener.nextUnwrapString(c)); + // 非引号包围,可能为boolean、数字、null等 + return null == value ? null : new JSONPrimitive(value); } - - /* - * 处理无引号包装的字符串,如: true, false, 或 null, 或 number. - * 同样兼容非标准的字符串,如key无引号包装。 - * 此方法会不断读取并积累字符直到遇到token符 - */ - return InternalJSONUtil.parseValueFromString(tokener.nextUnwrapString(c)); - } - - /** - * 对象构建抽象,通过实现此接口,从{@link JSONTokener}解析值并构建指定对象 - */ - @FunctionalInterface - public interface ObjectBuilder { - /** - * 构建 - * - * @param token 符号表示,用于区分对象类型 - * @param tokener {@link JSONTokener} - * @param config {@link JSONConfig} - * @return 构建的对象 - */ - Object build(char token, JSONTokener tokener, JSONConfig config); } } 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 2a05d2692..96ea999e4 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 @@ -244,12 +244,55 @@ public class JSONTokener extends ReaderWrapper { char c; while (true) { c = this.next(); - if (c == 0 || c > ' ') { + if (c == EOF || c > ' ') { return c; } } } + /** + * 读取下一个JSON中的key,支持不带引号的key + * + * @param c 当前字符 + * @return 键字符串 + * @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) { + // 不允许嵌套对象,如{{}}或{[]} + throw syntaxError("A JSONObject can not directly nest another JSONObject or JSONArray."); + } + case CharUtil.DOUBLE_QUOTES: + case CharUtil.SINGLE_QUOTE: + // 带有包装的key + return nextWrapString(c); + default: + // 兼容不严格的JSON,如key不被引号包围的情况 + return nextUnwrapString(c); + } + } + + /** + * 获取下一个冒号,非冒号则抛出异常 + * + * @throws JSONException 非冒号字符 + * @return 冒号字符 + */ + public char nextColon() throws JSONException { + final char c = nextClean(); + if (c != CharUtil.COLON) { + throw syntaxError("Expected a ':' after a key"); + } + return c; + } + /** * 读取一个字符串,包括: *
    @@ -265,7 +308,7 @@ public class JSONTokener extends ReaderWrapper { switch (c) { case CharUtil.DOUBLE_QUOTES: case CharUtil.SINGLE_QUOTE: - return nextString(c); + return nextWrapString(c); } // 兼容不严格的JSON,如key不被双引号包围的情况 @@ -311,7 +354,7 @@ public class JSONTokener extends ReaderWrapper { * @return 截止到引号前的字符串 * @throws JSONException 出现无结束的字符串时抛出此异常 */ - public String nextString(final char quote) throws JSONException { + public String nextWrapString(final char quote) throws JSONException { char c; final StringBuilder sb = new StringBuilder(); while (true) { 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 new file mode 100644 index 000000000..c98d118eb --- /dev/null +++ b/hutool-json/src/main/java/org/dromara/hutool/json/reader/OldJSONParser.java @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2013-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.core.lang.mutable.Mutable; +import org.dromara.hutool.core.lang.mutable.MutableEntry; +import org.dromara.hutool.core.text.CharUtil; +import org.dromara.hutool.json.*; + +import java.util.function.Predicate; + +/** + * JSON字符串解析器,实现: + *
      + *
    • JSON字符串 --> {@link JSONTokener} --> {@link JSONObject}
    • + *
    • JSON字符串 --> {@link JSONTokener} --> {@link JSONArray}
    • + *
    + * + * @author looly + * @since 5.8.0 + */ +public class OldJSONParser { + + /** + * 创建JSONParser + * + * @param tokener {@link JSONTokener} + * @param config JSON配置 + * @return JSONParser + */ + public static OldJSONParser of(final JSONTokener tokener, final JSONConfig config) { + return new OldJSONParser(tokener, config); + } + + /** + * JSON配置 + */ + private final JSONConfig config; + private final JSONTokener tokener; + + /** + * 构造 + * + * @param tokener {@link JSONTokener} + * @param config JSON配置 + */ + public OldJSONParser(final JSONTokener tokener, final JSONConfig config) { + this.tokener = tokener; + this.config = config; + } + + /** + * 获取{@link JSONTokener} + * + * @return {@link JSONTokener} + */ + public JSONTokener getTokener() { + return this.tokener; + } + + /** + * 是否结束 + * + * @return 是否结束 + */ + public boolean end() { + return this.tokener.end(); + } + + // region parseTo + + /** + * 解析{@link JSONTokener}中的字符到目标的{@link JSONObject}中 + * + * @param jsonObject {@link JSONObject} + * @param predicate 键值对过滤编辑器,可以通过实现此接口,完成解析前对键值对的过滤和修改操作,{@code null}表示不过滤,{@link Predicate#test(Object)}为{@code true}保留 + */ + public void parseTo(final JSONObject jsonObject, final Predicate> predicate) { + final JSONTokener tokener = this.tokener; + + if (tokener.nextClean() != '{') { + throw tokener.syntaxError("A JSONObject text must begin with '{'"); + } + + char prev; + char c; + String key; + while (true) { + prev = tokener.getPrevious(); + c = tokener.nextClean(); + switch (c) { + case 0: + throw tokener.syntaxError("A JSONObject text must end with '}'"); + case '}': + return; + case '{': + case '[': + if (prev == '{') { + throw tokener.syntaxError("A JSONObject can not directly nest another JSONObject or JSONArray."); + } + default: + tokener.back(); + key = tokener.nextString(); + } + + // The key is followed by ':'. + + c = tokener.nextClean(); + if (c != ':') { + throw tokener.syntaxError("Expected a ':' after a key"); + } + + jsonObject.set(key, nextValue(), predicate); + + // Pairs are separated by ','. + + switch (tokener.nextClean()) { + case ';': + case CharUtil.COMMA: + if (tokener.nextClean() == '}') { + // issue#2380 + // 尾后逗号(Trailing Commas),JSON中虽然不支持,但是ECMAScript 2017支持,此处做兼容。 + return; + } + tokener.back(); + break; + case '}': + return; + default: + throw tokener.syntaxError("Expected a ',' or '}'"); + } + } + } + + /** + * 解析JSON字符串到{@link JSONArray}中 + * + * @param jsonArray {@link JSONArray} + * @param predicate 键值对过滤编辑器,可以通过实现此接口,完成解析前对值的过滤和修改操作,{@code null} 表示不过滤,,{@link Predicate#test(Object)}为{@code true}保留 + */ + public void parseTo(final JSONArray jsonArray, final Predicate> predicate) { + final JSONTokener x = this.tokener; + + if (x.nextClean() != '[') { + throw x.syntaxError("A JSONArray text must start with '['"); + } + if (x.nextClean() != ']') { + x.back(); + for (; ; ) { + if (x.nextClean() == CharUtil.COMMA) { + x.back(); + jsonArray.add(null, predicate); + } else { + x.back(); + jsonArray.add(nextValue(), predicate); + } + switch (x.nextClean()) { + case CharUtil.COMMA: + if (x.nextClean() == ']') { + return; + } + x.back(); + break; + case ']': + return; + default: + throw x.syntaxError("Expected a ',' or ']'"); + } + } + } + } + // endregion + + /** + * 获得下一个值,值类型可以是Boolean, Double, Integer, JSONArray, JSONObject, Long, or String + * + * @return Boolean, Double, Integer, JSONArray, JSONObject, Long, or String + * @throws JSONException 语法错误 + */ + public Object nextValue() throws JSONException { + return nextValue((token, tokener, config) -> { + switch (token) { + case CharUtil.DELIM_START: + try { + return new JSONObject(this, config); + } catch (final StackOverflowError e) { + throw new JSONException("JSONObject depth too large to process.", e); + } + case CharUtil.BRACKET_START: + try { + return new JSONArray(this, config); + } catch (final StackOverflowError e) { + throw new JSONException("JSONObject depth too large to process.", e); + } + } + throw new JSONException("Unsupported object build for token {}", token); + }); + } + + /** + * 获得下一个值,值类型可以是Boolean, Double, Integer, JSONArray, JSONObject, Long, or String + * + * @param objectBuilder JSON对象构建器 + * @return Boolean, Double, Integer, JSONArray, JSONObject, Long, or String + * @throws JSONException 语法错误 + */ + public Object nextValue(final ObjectBuilder objectBuilder) throws JSONException { + final JSONTokener tokener = this.tokener; + final char c = tokener.nextClean(); + switch (c) { + case CharUtil.DOUBLE_QUOTES: + case CharUtil.SINGLE_QUOTE: + return tokener.nextWrapString(c); + case CharUtil.DELIM_START: + case CharUtil.BRACKET_START: + tokener.back(); + return objectBuilder.build(c, tokener, this.config); + } + + /* + * 处理无引号包装的字符串,如: true, false, 或 null, 或 number. + * 同样兼容非标准的字符串,如key无引号包装。 + * 此方法会不断读取并积累字符直到遇到token符 + */ + return InternalJSONUtil.parseValueFromString(tokener.nextUnwrapString(c)); + } + + /** + * 对象构建抽象,通过实现此接口,从{@link JSONTokener}解析值并构建指定对象 + */ + @FunctionalInterface + public interface ObjectBuilder { + /** + * 构建 + * + * @param token 符号表示,用于区分对象类型 + * @param tokener {@link JSONTokener} + * @param config {@link JSONConfig} + * @return 构建的对象 + */ + Object build(char token, JSONTokener tokener, JSONConfig config); + } +} diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/reader/package-info.java b/hutool-json/src/main/java/org/dromara/hutool/json/reader/package-info.java index f2f525753..acf025214 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/reader/package-info.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/reader/package-info.java @@ -15,7 +15,7 @@ */ /** - * JSON读取和解析 + * JSON读取和解析,主要解析字符串、流等JSON字符串为{@link org.dromara.hutool.json.JSON}。 * * @author Looly */