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

com.acgist.snail.format.JSON Maven / Gradle / Ivy

Go to download

基于Java开发的下载工具,支持下载协议:BT(BitTorrent、磁力链接、种子文件)、HLS(M3U8)、FTP、HTTP。

There is a newer version: 2.17.0
Show newest version
package com.acgist.snail.format;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import com.acgist.snail.utils.ArrayUtils;
import com.acgist.snail.utils.StringUtils;

/**
 * 

JSON工具

* * @author acgist */ public final class JSON { /** *

JSON特殊字符

*

Chrome浏览器控制台执行以下代码获取特殊字符:

*
	 * var array = {};
	 * for (var i = 0, value = '', array = []; i < 0xFFFF; i++) {
	 * 	if(i >= 0xD800 && i <= 0xDFFF) {
	 * 		continue;
	 * 	}
	 * 	value = JSON.stringify(String.fromCharCode(i));
	 * 	value.indexOf("\\") > -1 && array.push(value);
	 * }
	 * console.log(array.join(", "));
	 * 
*

其他特殊字符(不处理):D800~DFFF

*/ private static final char[] CHARS = new char[] { '\u0000', '\u0001', '\u0002', '\u0003', '\u0004', '\u0005', '\u0006', '\u0007', '\b', '\t', '\n', '\u000b', '\f', '\r', '\u000e', '\u000f', '\u0010', '\u0011', '\u0012', '\u0013', '\u0014', '\u0015', '\u0016', '\u0017', '\u0018', '\u0019', '\u001a', '\u001b', '\u001c', '\u001d', '\u001e', '\u001f', '\"', '\\' }; /** *

特殊字符对应编码

*/ private static final String[] CHARS_ESCAPE = new String[] { "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", "\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012", "\\u0013", "\\u0014", "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", "\\u001a", "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f", "\\\"", "\\\\" }; /** *

转义字符串:{@value}

*/ private static final char JSON_ESCAPE = '\\'; /** *

{@link Map}前缀:{@value}

*/ private static final char JSON_MAP_PREFIX = '{'; /** *

{@link Map}后缀:{@value}

*/ private static final char JSON_MAP_SUFFIX = '}'; /** *

{@link List}前缀:{@value}

*/ private static final char JSON_LIST_PREFIX = '['; /** *

{@link List}后缀:{@value}

*/ private static final char JSON_LIST_SUFFIX = ']'; /** *

键值分隔符:{@value}

*/ private static final char JSON_KV_SEPARATOR = ':'; /** *

属性分隔符:{@value}

*/ private static final char JSON_ATTR_SEPARATOR = ','; /** *

字符串:{@value}

*/ private static final char JSON_STRING = '"'; /** *

空值:{@value}

*/ private static final String JSON_NULL = "null"; /** *

boolean类型:{@value}

*/ private static final String JSON_BOOLEAN_TRUE = "true"; /** *

boolean类型:{@value}

*/ private static final String JSON_BOOLEAN_FALSE = "false"; /** *

JSON数据类型

* * @author acgist */ public enum Type { /** *

Map

*/ MAP, /** *

List

*/ LIST; } /** *

类型

*/ private Type type; /** *

List

*/ private List list; /** *

Map

*/ private Map map; /** *

是否使用懒加载

*

懒加载:反序列化JSON时不会立即解析所有的JSON对象

*/ private static boolean lazy = true; private JSON() { } /** *

使用Map生成JSON对象

* * @param map {@link Map} * * @return JSON对象 */ public static final JSON ofMap(Map map) { final JSON json = new JSON(); json.map = map; json.type = Type.MAP; return json; } /** *

使用List生成JSON对象

* * @param list {@link List} * * @return JSON对象 */ public static final JSON ofList(List list) { final JSON json = new JSON(); json.list = list; json.type = Type.LIST; return json; } /** *

将字符串转为为JSON对象

* * @param content 字符串 * * @return JSON对象 */ public static final JSON ofString(String content) { if(StringUtils.isEmpty(content)) { throw new IllegalArgumentException("JSON格式错误:" + content); } content = content.trim(); if(content.isEmpty()) { throw new IllegalArgumentException("JSON格式错误:" + content); } final JSON json = new JSON(); final char prefix = content.charAt(0); final char suffix = content.charAt(content.length() - 1); if(prefix == JSON_MAP_PREFIX && suffix == JSON_MAP_SUFFIX) { json.type = Type.MAP; } else if(prefix == JSON_LIST_PREFIX && suffix == JSON_LIST_SUFFIX) { json.type = Type.LIST; } else { throw new IllegalArgumentException("JSON格式错误:" + content); } // 去掉首尾字符 content = content.substring(1, content.length() - 1); json.deserialize(content); return json; } /** *

使用懒加载

*/ public static final void lazy() { JSON.lazy = true; } /** *

禁用懒加载

*/ public static final void eager() { JSON.lazy = false; } /** *

序列化JSON对象

* * @return JSON字符串 */ private String serialize() { final StringBuilder builder = new StringBuilder(); if(this.type == Type.MAP) { serializeMap(this.map, builder); } else if(this.type == Type.LIST) { serializeList(this.list, builder); } else { throw new IllegalArgumentException("JSON类型错误:" + this.type); } return builder.toString(); } /** *

序列化Map

* * @param map Map * @param builder JSON字符串Builder */ private static final void serializeMap(Map map, StringBuilder builder) { Objects.requireNonNull(map, "JSON序列化Map失败"); builder.append(JSON_MAP_PREFIX); if(!map.isEmpty()) { map.forEach((key, value) -> { serializeValue(key, builder); builder.append(JSON_KV_SEPARATOR); serializeValue(value, builder); builder.append(JSON_ATTR_SEPARATOR); }); builder.setLength(builder.length() - 1); } builder.append(JSON_MAP_SUFFIX); } /** *

序列化List

* * @param list List * @param builder JSON字符串Builder */ private static final void serializeList(List list, StringBuilder builder) { Objects.requireNonNull(list, "JSON序列化List失败"); builder.append(JSON_LIST_PREFIX); if(!list.isEmpty()) { list.forEach(value -> { serializeValue(value, builder); builder.append(JSON_ATTR_SEPARATOR); }); builder.setLength(builder.length() - 1); } builder.append(JSON_LIST_SUFFIX); } /** *

序列化Java对象

* * @param object Java对象 * @param builder JSON字符串Builder */ private static final void serializeValue(Object object, StringBuilder builder) { if(object instanceof String string) { builder .append(JSON_STRING) .append(escapeValue(string)) .append(JSON_STRING); } else if(object instanceof Number) { builder.append(object.toString()); } else if(object instanceof Boolean) { builder.append(object.toString()); } else if(object instanceof JSON) { builder.append(object.toString()); } else if(object instanceof Map map) { serializeMap(map, builder); } else if(object instanceof List list) { serializeList(list, builder); } else if(object == null) { builder.append(JSON_NULL); } else { builder .append(JSON_STRING) .append(escapeValue(object.toString())) .append(JSON_STRING); } } /** *

反序列化JSON字符串

* * @param content JSON字符串 */ private void deserialize(String content) { if(this.type == Type.MAP) { this.map = new LinkedHashMap<>(); deserializeMap(content, this.map); } else if(this.type == Type.LIST) { this.list = new ArrayList<>(); deserializeList(content, this.list); } else { throw new IllegalArgumentException("JSON类型错误:" + this.type); } } /** *

反序列化Map

* * @param content JSON字符串 * @param map Map */ private static final void deserializeMap(String content, Map map) { content = unescapeValue(content); final int length = content.length(); final AtomicInteger index = new AtomicInteger(0); while(index.get() < length) { map.put( deserializeValue(index, content), deserializeValue(index, content) ); } } /** *

反序列化List

* * @param content JSON字符串 * @param list List */ private static final void deserializeList(String content, List list) { content = unescapeValue(content); final int length = content.length(); final AtomicInteger index = new AtomicInteger(0); while(index.get() < length) { list.add( deserializeValue(index, content) ); } } /** *

反序列化JSON字符串

* * @param index 字符索引 * @param content JSON字符串 * * @return Java对象 */ private static final Object deserializeValue(AtomicInteger index, String content) { char value; String hexValue; // JSON层级 int jsonIndex = 0; // String层级 int stringIndex = 0; final int length = content.length(); final StringBuilder builder = new StringBuilder(); do { value = content.charAt(index.get()); if(value == JSON_STRING) { if(stringIndex == 0) { stringIndex++; } else { stringIndex--; } } else if(value == JSON_MAP_PREFIX || value == JSON_LIST_PREFIX) { jsonIndex++; } else if(value == JSON_MAP_SUFFIX || value == JSON_LIST_SUFFIX) { jsonIndex--; } // 结束循环 if(stringIndex == 0 && jsonIndex == 0 && (value == JSON_KV_SEPARATOR || value == JSON_ATTR_SEPARATOR)) { index.incrementAndGet(); break; } // 转义参考:#CHARS if (value == JSON_ESCAPE) { value = content.charAt(index.incrementAndGet()); switch (value) { case 'b' -> builder.append('\b'); case 't' -> builder.append('\t'); case 'n' -> builder.append('\n'); case 'f' -> builder.append('\f'); case 'r' -> builder.append('\r'); case '"', JSON_ESCAPE -> { // 如果存在JSON对象里面保留转义字符 if(jsonIndex != 0) { builder.append(JSON_ESCAPE); } builder.append(value); } case 'u' -> { // Unicode hexValue = content.substring(index.get() + 1, index.get() + 5); builder.append((char) Integer.parseInt(hexValue, 16)); index.addAndGet(4); } default -> { // 未知转义类型保留转义字符 builder.append(JSON_ESCAPE); builder.append(value); } } } else { builder.append(value); } } while (index.incrementAndGet() < length); return deserializeValue(builder.toString()); } /** *

类型转换

*

注意顺序:优先判断等于,然后判断equals,最后判断数值(正则表达式)。

* * @param content JSON字符串 * * @return Java对象 */ private static final Object deserializeValue(String content) { final String value = content.trim(); final int length = value.length(); char first = '0'; char last = '0'; if(length > 1) { first = value.charAt(0); last = value.charAt(length - 1); } if(first == JSON_STRING && last == JSON_STRING) { return value.substring(1, length - 1); } else if( (first == JSON_MAP_PREFIX && last == JSON_MAP_SUFFIX) || (first == JSON_LIST_PREFIX && last == JSON_LIST_SUFFIX) ) { if(JSON.lazy) { return value; } else { return JSON.ofString(value); } } else if(JSON_BOOLEAN_TRUE.equals(value) || JSON_BOOLEAN_FALSE.equals(value)) { return Boolean.valueOf(value); } else if(JSON_NULL.equals(value)) { return null; } else if(StringUtils.isDecimal(value)) { return Integer.valueOf(value); } else { throw new IllegalArgumentException("JSON格式错误:" + value); } } /** *

转义JSON字符串

* * @param content 原始字符串 * * @return 转义字符串 * * @see #CHARS * @see #CHARS_ESCAPE */ private static final StringBuilder escapeValue(String content) { final char[] chars = content.toCharArray(); final StringBuilder builder = new StringBuilder(); for (char value : chars) { // #CHARS if(value > 0x1F && value != 0x22 && value != 0x5C) { builder.append(value); } else { builder.append(CHARS_ESCAPE[ArrayUtils.indexOf(CHARS, value)]); } } return builder; } /** *

反转义JSON字符串

* * @param content 转义字符串 * * @return 原始字符串 * * @see #CHARS * @see #CHARS_ESCAPE */ private static final String unescapeValue(String content) { if(content.charAt(0) == JSON_ESCAPE) { for (int index = 0; index < CHARS_ESCAPE.length; index++) { content = content.replace(CHARS_ESCAPE[index], String.valueOf(CHARS[index])); } } return content; } /** *

获取Map

* * @return Map */ public Map getMap() { return this.map; } /** *

获取List

* * @return List */ public List getList() { return this.list; } /** *

获取JSON对象

* * @param key 属性名称 * * @return JSON对象 */ public JSON getJSON(Object key) { final Object value = this.get(key); if(value == null) { return null; } else if(value instanceof JSON json) { return json; } else if(value instanceof String string) { return JSON.ofString(string); } else if(value instanceof Map map) { final Map valueMap = map.entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> b, LinkedHashMap::new)); return JSON.ofMap(valueMap); } else if(value instanceof List list) { final List valueList = list.stream() .collect(Collectors.toList()); return JSON.ofList(valueList); } else { throw new IllegalArgumentException("JSON转换错误:" + value); } } /** *

获取Integer属性对象

* * @param key 属性名称 * * @return Integer */ public Integer getInteger(Object key) { return (Integer) this.get(key); } /** *

获取Boolean属性对象

* * @param key 属性名称 * * @return Boolean */ public Boolean getBoolean(Object key) { return (Boolean) this.get(key); } /** *

获取String属性对象

* * @param key 属性名称 * * @return String */ public String getString(Object key) { return (String) this.get(key); } /** *

获取属性对象

* * @param key 属性名称 * * @return 属性对象 */ public Object get(Object key) { return this.map.get(key); } /** * @return JSON字符串 */ public String toJSON() { return this.serialize(); } @Override public String toString() { return this.serialize(); } }