All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dromara.hutool.json.JSONParser Maven / Gradle / Ivy

There is a newer version: 6.0.0.M3
Show newest version
/*
 * 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;

import org.dromara.hutool.core.lang.mutable.Mutable;
import org.dromara.hutool.core.lang.mutable.MutableEntry;
import org.dromara.hutool.core.text.CharUtil;

import java.util.function.Predicate;

/**
 * JSON字符串解析器,实现:
 * 
    *
  • JSON字符串 --> {@link JSONTokener} --> {@link JSONObject}
  • *
  • JSON字符串 --> {@link JSONTokener} --> {@link JSONArray}
  • *
* * @author looly * @since 5.8.0 */ public class JSONParser { /** * JSON配置 */ private final JSONConfig config; /** * 创建JSONParser * * @param tokener {@link JSONTokener} * @param config JSON配置 * @return JSONParser */ public static JSONParser of(final JSONTokener tokener, final JSONConfig config) { return new JSONParser(tokener, config); } private final JSONTokener tokener; /** * 构造 * * @param tokener {@link JSONTokener} * @param config JSON配置 */ public JSONParser(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.addRaw(null, predicate); } else { x.back(); jsonArray.addRaw(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.nextString(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); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy