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

org.dromara.hutool.json.InternalJSONUtil 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.array.ArrayUtil;
import org.dromara.hutool.core.bean.copier.CopyOptions;
import org.dromara.hutool.core.codec.binary.HexUtil;
import org.dromara.hutool.core.convert.ConvertUtil;
import org.dromara.hutool.core.io.IORuntimeException;
import org.dromara.hutool.core.lang.mutable.MutableEntry;
import org.dromara.hutool.core.map.CaseInsensitiveLinkedMap;
import org.dromara.hutool.core.map.CaseInsensitiveTreeMap;
import org.dromara.hutool.core.math.NumberUtil;
import org.dromara.hutool.core.reflect.ConstructorUtil;
import org.dromara.hutool.core.reflect.TypeUtil;
import org.dromara.hutool.core.text.CharUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.text.split.SplitUtil;
import org.dromara.hutool.json.serialize.GlobalSerializeMapping;
import org.dromara.hutool.json.serialize.JSONDeserializer;
import org.dromara.hutool.json.serialize.JSONStringer;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Predicate;

/**
 * 内部JSON工具类,仅用于JSON内部使用
 *
 * @author Looly
 */
public final class InternalJSONUtil {

	/**
	 * 尝试转换字符串为number, boolean, or null,无法转换返回String
* 此方法用于解析JSON字符串时,将字符串中的值转换为JSON值对象 * * @param string A String. * @return A simple JSON value. */ public static Object parseValueFromString(final String string) { // null处理 if (StrUtil.isEmpty(string) || StrUtil.NULL.equalsIgnoreCase(string)) { return null; } // boolean处理 if ("true".equalsIgnoreCase(string)) { return Boolean.TRUE; } if ("false".equalsIgnoreCase(string)) { return Boolean.FALSE; } // Number处理 final char b = string.charAt(0); if ((b >= '0' && b <= '9') || b == '-') { try { if (StrUtil.containsAnyIgnoreCase(string, ".", "e")) { // pr#192@Gitee,Double会出现小数精度丢失问题,此处使用BigDecimal return new BigDecimal(string); } else { final long myLong = Long.parseLong(string); if (string.equals(Long.toString(myLong))) { if (myLong == (int) myLong) { return (int) myLong; } else { return myLong; } } } } catch (final Exception ignore) { } } // 其它情况返回原String值下 return string; } /** * 值转为String,用于JSON中。规则为: *
    *
  • 对象如果实现了{@link JSONStringer}接口,调用{@link JSONStringer#toJSONString()}方法
  • *
  • 对象如果实现了{@link JSONStringer}接口,调用{@link JSONStringer#toJSONString()}方法
  • *
  • 对象如果是数组或Collection,包装为{@link JSONArray}
  • *
  • 对象如果是Map,包装为{@link JSONObject}
  • *
  • 对象如果是数字,使用{@link NumberUtil#toStr(Number)}转换为字符串
  • *
  • 其他情况调用toString并使用双引号包装
  • *
* * @param value 需要转为字符串的对象 * @return 字符串 * @throws JSONException If the value is or contains an invalid number. */ static String valueToString(final Object value) throws JSONException { if (value == null) { return StrUtil.NULL; } if (value instanceof JSONStringer) { try { return ((JSONStringer) value).toJSONString(); } catch (final Exception e) { throw new JSONException(e); } } else if (value instanceof Number) { return NumberUtil.toStr((Number) value); } else if (value instanceof Boolean || value instanceof JSONObject || value instanceof JSONArray) { return value.toString(); } else if (value instanceof Map) { final Map map = (Map) value; return new JSONObject(map).toString(); } else if (value instanceof Collection) { final Collection coll = (Collection) value; return new JSONArray(coll).toString(); } else if (ArrayUtil.isArray(value)) { return new JSONArray(value).toString(); } else { return quote(value.toString()); } } /** * 将Property的键转化为JSON形式
* 用于识别类似于:org.dromara.hutool.json这类用点隔开的键
* 注意:不允许重复键 * * @param jsonObject JSONObject * @param key 键 * @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) { final String[] path = SplitUtil.splitToArray(ConvertUtil.toStr(key), StrUtil.DOT); final int last = path.length - 1; JSONObject target = jsonObject; for (int i = 0; i < last; i += 1) { final String segment = path[i]; JSONObject nextTarget = target.getJSONObject(segment); if (nextTarget == null) { nextTarget = new JSONObject(target.config()); target.set(segment, nextTarget, predicate); } target = nextTarget; } target.set(path[last], value, predicate); } /** * 默认情况下是否忽略null值的策略选择,以下对象不忽略null值,其它对象忽略: * *
	 *     1. CharSequence
	 *     2. JSONTokener
	 *     3. Map
	 * 
* * @param obj 需要检查的对象 * @return 是否忽略null值 * @since 4.3.1 */ static boolean defaultIgnoreNullValue(final Object obj) { return (!(obj instanceof CharSequence))// && (!(obj instanceof JSONTokener))// && (!(obj instanceof Map)); } /** * 将{@link JSONConfig}参数转换为Bean拷贝所用的{@link CopyOptions} * * @param config {@link JSONConfig} * @return {@link CopyOptions} * @since 5.8.0 */ public static CopyOptions toCopyOptions(final JSONConfig config) { return CopyOptions.of() .setIgnoreCase(config.isIgnoreCase()) .setIgnoreError(config.isIgnoreError()) .setIgnoreNullValue(config.isIgnoreNullValue()) .setTransientSupport(config.isTransientSupport()) // 使用JSON转换器 .setConverter(config.getConverter()); } /** * 对所有双引号做转义处理(使用双反斜杠做转义)
* 为了能在HTML中较好的显示,会将</转义为<\/
* JSON字符串中不能包含控制字符和未经转义的引号和反斜杠 * * @param string 字符串 * @return 适合在JSON中显示的字符串 */ public static String quote(final CharSequence string) { return quote(string, true); } /** * 对所有双引号做转义处理(使用双反斜杠做转义)
* 为了能在HTML中较好的显示,会将</转义为<\/
* JSON字符串中不能包含控制字符和未经转义的引号和反斜杠 * * @param string 字符串 * @param isWrap 是否使用双引号包装字符串 * @return 适合在JSON中显示的字符串 * @since 3.3.1 */ public static String quote(final CharSequence string, final boolean isWrap) { return quote(string, new StringWriter(), isWrap).toString(); } /** * 对所有双引号做转义处理(使用双反斜杠做转义)
* 为了能在HTML中较好的显示,会将</转义为<\/
* JSON字符串中不能包含控制字符和未经转义的引号和反斜杠 * * @param str 字符串 * @param writer Writer * @throws IORuntimeException IO异常 */ public static void quote(final CharSequence str, final Writer writer) throws IORuntimeException { quote(str, writer, true); } /** * 对所有双引号做转义处理(使用双反斜杠做转义)
* 为了能在HTML中较好的显示,会将</转义为<\/
* JSON字符串中不能包含控制字符和未经转义的引号和反斜杠 * * @param str 字符串 * @param writer Writer * @param isWrap 是否使用双引号包装字符串 * @return Writer * @throws IORuntimeException IO异常 * @since 3.3.1 */ public static Writer quote(final CharSequence str, final Writer writer, final boolean isWrap) throws IORuntimeException { try { return _quote(str, writer, isWrap); } catch (final IOException e) { throw new IORuntimeException(e); } } /** * 转义显示不可见字符 * * @param str 字符串 * @return 转义后的字符串 */ public static String escape(final String str) { if (StrUtil.isEmpty(str)) { return str; } final int len = str.length(); final StringBuilder builder = new StringBuilder(len); char c; for (int i = 0; i < len; i++) { c = str.charAt(i); builder.append(escape(c)); } return builder.toString(); } /** * 根据配置创建对应的原始Map * * @param capacity 初始大小 * @param config JSON配置项,{@code null}则使用默认配置 * @return Map */ static Map createRawMap(final int capacity, JSONConfig config) { final Map rawHashMap; if (null == config) { config = JSONConfig.of(); } final Comparator keyComparator = config.getKeyComparator(); if (config.isIgnoreCase()) { if (null != keyComparator) { rawHashMap = new CaseInsensitiveTreeMap<>(keyComparator); } else { rawHashMap = new CaseInsensitiveLinkedMap<>(capacity); } } else { if (null != keyComparator) { rawHashMap = new TreeMap<>(keyComparator); } else { rawHashMap = new LinkedHashMap<>(capacity); } } return rawHashMap; } /** * 根据目标类型,获取对应的{@link JSONDeserializer},首先判断是否实现了{@link JSONDeserializer}接口
* 如果未实现从{@link GlobalSerializeMapping}中查找全局的{@link JSONDeserializer},否则返回null * * @param targetType 目标类型 * @param 目标类型 * @return {@link JSONDeserializer} */ @SuppressWarnings("unchecked") public static JSONDeserializer getDeserializer(final Type targetType) { final Class rawType = (Class) TypeUtil.getClass(targetType); if (null != rawType && JSONDeserializer.class.isAssignableFrom(rawType)) { return (JSONDeserializer) ConstructorUtil.newInstanceIfPossible(rawType); } // 全局自定义反序列化(优先级低于实现JSONDeserializer接口) return (JSONDeserializer) GlobalSerializeMapping.getDeserializer(targetType); } // --------------------------------------------------------------------------------------------- Private method start /** * 对所有双引号做转义处理(使用双反斜杠做转义)
* 为了能在HTML中较好的显示,会将</转义为<\/
* JSON字符串中不能包含控制字符和未经转义的引号和反斜杠 * * @param str 字符串 * @param writer Writer * @param isWrap 是否使用双引号包装字符串 * @return Writer * @throws IOException IO异常 * @since 3.3.1 */ private static Writer _quote(final CharSequence str, final Writer writer, final boolean isWrap) throws IOException { if (StrUtil.isEmpty(str)) { if (isWrap) { writer.write("\"\""); } return writer; } char c; // 当前字符 final int len = str.length(); if (isWrap) { writer.write('"'); } for (int i = 0; i < len; i++) { c = str.charAt(i); switch (c) { case '\\': case '"': writer.write("\\"); writer.write(c); break; default: writer.write(escape(c)); } } if (isWrap) { writer.write('"'); } return writer; } /** * 转义不可见字符
* 见:https://en.wikibooks.org/wiki/Unicode/Character_reference/0000-0FFF * * @param c 字符 * @return 转义后的字符串 */ @SuppressWarnings("UnnecessaryUnicodeEscape") private static String escape(final char c) { switch (c) { case '\b': return "\\b"; case '\t': return "\\t"; case '\n': return "\\n"; case '\f': return "\\f"; case '\r': return "\\r"; default: if (c < CharUtil.SPACE || // (c >= '\u0080' && c <= '\u00a0') || // (c >= '\u2000' && c <= '\u2010') || // (c >= '\u2028' && c <= '\u202F') || // (c >= '\u2066' && c <= '\u206F')// ) { return HexUtil.toUnicodeHex(c); } else { return Character.toString(c); } } } // --------------------------------------------------------------------------------------------- Private method end }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy