From aa48d3f2ffabdeacf61f0bcf52b81ca31dc04aee Mon Sep 17 00:00:00 2001 From: Looly Date: Sat, 16 Apr 2022 09:27:47 +0800 Subject: [PATCH] add parser --- CHANGELOG.md | 3 +- .../main/java/cn/hutool/json/JSONArray.java | 41 ++---- .../main/java/cn/hutool/json/JSONObject.java | 43 +------ .../main/java/cn/hutool/json/JSONParser.java | 119 ++++++++++++++++++ .../main/java/cn/hutool/json/JSONTokener.java | 2 +- 5 files changed, 136 insertions(+), 72 deletions(-) create mode 100755 hutool-json/src/main/java/cn/hutool/json/JSONParser.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 04520ca7d..7dd9e5c31 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,12 +3,13 @@ ------------------------------------------------------------------------------------------------------------- -# 5.8.0.M4 (2022-04-15) +# 5.8.0.M4 (2022-04-16) ### ❌不兼容特性 ### 🐣新特性 * 【core 】 BeanUtil增加toBean重载(pr#598@Gitee) +* 【json 】 新增JSONParser ### 🐞Bug修复 diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONArray.java b/hutool-json/src/main/java/cn/hutool/json/JSONArray.java index c5412c57d..55b367082 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONArray.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONArray.java @@ -385,7 +385,7 @@ public class JSONArray implements JSON, JSONGetter, List, Rando @Override public boolean add(Object e) { - return this.rawList.add(JSONUtil.wrap(e, this.config)); + return addRaw(JSONUtil.wrap(e, this.config)); } @Override @@ -592,6 +592,17 @@ public class JSONArray implements JSON, JSONGetter, List, Rando } // ------------------------------------------------------------------------------------------------- Private method start + /** + * 原始添加,添加的对象不做任何处理 + * + * @param obj 添加的对象 + * @return 是否加入成功 + * @since 5.8.0 + */ + protected boolean addRaw(Object obj) { + return this.rawList.add(obj); + } + /** * 初始化 * @@ -653,33 +664,7 @@ public class JSONArray implements JSON, JSONGetter, List, Rando * @param x {@link JSONTokener} */ private void init(JSONTokener x) { - if (x.nextClean() != '[') { - throw x.syntaxError("A JSONArray text must start with '['"); - } - if (x.nextClean() != ']') { - x.back(); - for (; ; ) { - if (x.nextClean() == ',') { - x.back(); - this.rawList.add(JSONNull.NULL); - } else { - x.back(); - this.rawList.add(x.nextValue()); - } - switch (x.nextClean()) { - case ',': - if (x.nextClean() == ']') { - return; - } - x.back(); - break; - case ']': - return; - default: - throw x.syntaxError("Expected a ',' or ']'"); - } - } - } + JSONParser.of(x).parseTo(this); } // ------------------------------------------------------------------------------------------------- Private method end } diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONObject.java b/hutool-json/src/main/java/cn/hutool/json/JSONObject.java index ddb41a42e..d3a3311ae 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONObject.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONObject.java @@ -646,48 +646,7 @@ public class JSONObject extends MapWrapper implements JSON, JSON * @param x JSONTokener */ private void init(JSONTokener x) { - char c; - String key; - - if (x.nextClean() != '{') { - throw x.syntaxError("A JSONObject text must begin with '{'"); - } - while (true) { - c = x.nextClean(); - switch (c) { - case 0: - throw x.syntaxError("A JSONObject text must end with '}'"); - case '}': - return; - default: - x.back(); - key = x.nextValue().toString(); - } - - // The key is followed by ':'. - - c = x.nextClean(); - if (c != ':') { - throw x.syntaxError("Expected a ':' after a key"); - } - this.putOnce(key, x.nextValue()); - - // Pairs are separated by ','. - - switch (x.nextClean()) { - case ';': - case ',': - if (x.nextClean() == '}') { - return; - } - x.back(); - break; - case '}': - return; - default: - throw x.syntaxError("Expected a ',' or '}'"); - } - } + JSONParser.of(x).parseTo(this); } /** diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONParser.java b/hutool-json/src/main/java/cn/hutool/json/JSONParser.java new file mode 100755 index 000000000..16db58bbb --- /dev/null +++ b/hutool-json/src/main/java/cn/hutool/json/JSONParser.java @@ -0,0 +1,119 @@ +package cn.hutool.json; + +/** + * JSON字符串解析器 + * + * @author looly + * @since 5.8.0 + */ +public class JSONParser { + private final JSONTokener tokener; + + /** + * 创建JSONParser + * + * @param tokener {@link JSONTokener} + * @return JSONParser + */ + public static JSONParser of(JSONTokener tokener) { + return new JSONParser(tokener); + } + + /** + * 构造 + * + * @param tokener {@link JSONTokener} + */ + public JSONParser(JSONTokener tokener) { + this.tokener = tokener; + } + + /** + * 解析{@link JSONTokener}中的字符到目标的{@link JSONObject}中 + * + * @param jsonObject {@link JSONObject} + */ + public void parseTo(JSONObject jsonObject) { + final JSONTokener tokener = this.tokener; + + char c; + String key; + + if (tokener.nextClean() != '{') { + throw tokener.syntaxError("A JSONObject text must begin with '{'"); + } + while (true) { + c = tokener.nextClean(); + switch (c) { + case 0: + throw tokener.syntaxError("A JSONObject text must end with '}'"); + case '}': + return; + default: + tokener.back(); + key = tokener.nextValue().toString(); + } + + // The key is followed by ':'. + + c = tokener.nextClean(); + if (c != ':') { + throw tokener.syntaxError("Expected a ':' after a key"); + } + jsonObject.putOnce(key, tokener.nextValue()); + + // Pairs are separated by ','. + + switch (tokener.nextClean()) { + case ';': + case ',': + if (tokener.nextClean() == '}') { + return; + } + tokener.back(); + break; + case '}': + return; + default: + throw tokener.syntaxError("Expected a ',' or '}'"); + } + } + } + + /** + * 解析JSON字符串到{@link JSONArray}中 + * + * @param jsonArray {@link JSONArray} + */ + public void parseTo(JSONArray jsonArray) { + 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() == ',') { + x.back(); + jsonArray.addRaw(JSONNull.NULL); + } else { + x.back(); + jsonArray.addRaw(x.nextValue()); + } + switch (x.nextClean()) { + case ',': + if (x.nextClean() == ']') { + return; + } + x.back(); + break; + case ']': + return; + default: + throw x.syntaxError("Expected a ',' or ']'"); + } + } + } + } +} diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java b/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java index fd5acd111..fbc1e58eb 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java @@ -217,7 +217,7 @@ public class JSONTokener { * 返回当前位置到指定引号前的所有字符,反斜杠的转义符也会被处理。
* 标准的JSON是不允许使用单引号包含字符串的,但是此实现允许。 * - * @param quote 字符引号, 包括 "(双引号) 或 '(单引号)。 + * @param quote 字符引号, 包括 {@code "}(双引号) 或 {@code '}(单引号)。 * @return 截止到引号前的字符串 * @throws JSONException 出现无结束的字符串时抛出此异常 */