Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.acgist.snail.system.JSON Maven / Gradle / Ivy
package com.acgist.snail.system;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.acgist.snail.system.exception.ArgumentException;
import com.acgist.snail.utils.ArrayUtils;
import com.acgist.snail.utils.StringUtils;
/**
* JSON处理工具
*
* @author acgist
* @since 1.2.0
*/
public class JSON {
private static final Logger LOGGER = LoggerFactory.getLogger(JSON.class);
/**
* 特殊字符
* Chrome浏览器控制台执行:
*
for (var i = 0, value = '', array = []; i < 0xFFFF; i++) {
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_ENCODE = 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",
"\\\"", "\\\\"
};
/**
* Map前缀
*/
private static final char JSON_MAP_PREFIX = '{';
/**
* Map后缀
*/
private static final char JSON_MAP_SUFFIX = '}';
/**
* List前缀
*/
private static final char JSON_LIST_PREFIX = '[';
/**
* List后缀
*/
private static final char JSON_LIST_SUFFIX = ']';
/**
* JSON:键值分隔符
*/
private static final char JSON_KV = ':';
/**
* JSON:属性分隔符
*/
private static final char JSON_ATTR = ',';
/**
* JSON:字符串
*/
private static final char JSON_STRING = '"';
/**
* JSON:boolean:true
*/
private static final String JSON_BOOLEAN_TRUE = "true";
/**
* JSON:boolean:false
*/
private static final String JSON_BOOLEAN_FALSE = "false";
/**
* JSON:null
*/
private static final String JSON_NULL = "null";
/**
* 类型
*/
public enum Type {
/** map */
map,
/** list */
list;
}
private Type type;
private Map map;
private List list;
private JSON() {
}
public static final JSON ofMap(Map map) {
final JSON json = new JSON();
json.map = map;
json.type = Type.map;
return json;
}
public static final JSON ofList(List list) {
final JSON json = new JSON();
json.list = list;
json.type = Type.list;
return json;
}
public static final JSON ofString(String content) {
if(StringUtils.isEmpty(content)) {
throw new ArgumentException("JSON格式错误:" + content);
}
content = content.trim();
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 ArgumentException("JSON格式错误(类型):" + content);
}
content = content.substring(1, content.length() - 1); // 去掉首位字符
json.deserialize(content);
return json;
}
/**
* 序列化
*/
private String serialize() {
final StringBuilder builder = new StringBuilder();
if(this.type == Type.map) {
this.serializeMap(this.map, builder);
} else if(this.type == Type.list) {
this.serializeList(this.list, builder);
} else {
throw new ArgumentException("JSON类型错误:" + this.type);
}
return builder.toString();
}
private void serializeMap(Map, ?> map, StringBuilder builder) {
if(map == null) {
throw new ArgumentException("JSON序列化错误:Map=null");
}
builder.append(JSON_MAP_PREFIX);
if(!map.isEmpty()) {
map.entrySet().forEach(entry -> {
serializeValue(entry.getKey(), builder);
builder.append(JSON_KV);
serializeValue(entry.getValue(), builder);
builder.append(JSON_ATTR);
});
builder.setLength(builder.length() - 1);
}
builder.append(JSON_MAP_SUFFIX);
}
private void serializeList(List> list, StringBuilder builder) {
if(list == null) {
throw new ArgumentException("JSON序列化错误:List=null");
}
builder.append(JSON_LIST_PREFIX);
if(!list.isEmpty()) {
list.forEach(value -> {
serializeValue(value, builder);
builder.append(JSON_ATTR);
});
builder.setLength(builder.length() - 1);
}
builder.append(JSON_LIST_SUFFIX);
}
/**
* 序列化JSON属性
*/
private void serializeValue(Object object, StringBuilder builder) {
if(object == null) {
builder.append(JSON_NULL);
} else if(object instanceof String) {
builder.append(JSON_STRING).append(serializeValue((String) object)).append(JSON_STRING);
} else if(object instanceof Boolean) {
builder.append(object.toString());
} else if(object instanceof Number) {
builder.append(object.toString());
} else if(object instanceof JSON) {
builder.append(object.toString());
} else if(object instanceof Map) {
serializeMap((Map, ?>) object, builder);
} else if(object instanceof List) {
serializeList((List>) object, builder);
} else {
builder.append(JSON_STRING).append(serializeValue(object.toString())).append(JSON_STRING);
}
}
/**
* 转义字符
*/
private String serializeValue(String content) {
int index = -1;
final char[] chars = content.toCharArray();
final StringBuilder builder = new StringBuilder();
for (char value : chars) {
index = ArrayUtils.indexOf(CHARS, value);
if(index == ArrayUtils.NO_INDEX) {
builder.append(value);
} else {
builder.append(CHARS_ENCODE[index]);
}
}
return builder.toString();
}
/**
* 反序列化
*/
private void deserialize(String content) {
if(this.type == Type.map) {
deserializeMap(content);
} else if(this.type == Type.list) {
deserializeList(content);
} else {
throw new ArgumentException("JSON类型错误:" + this.type);
}
}
private void deserializeMap(String content) {
this.map = new LinkedHashMap<>();
final AtomicInteger index = new AtomicInteger(0);
while(index.get() < content.length()) {
this.map.put(
deserializeValue(index, content),
deserializeValue(index, content)
);
}
}
private void deserializeList(String content) {
this.list = new ArrayList<>();
final AtomicInteger index = new AtomicInteger(0);
while(index.get() < content.length()) {
this.list.add(
deserializeValue(index, content)
);
}
}
/**
* 解析JSON属性
*/
private Object deserializeValue(AtomicInteger index, String content) {
char value;
boolean string = false; // 是否是字符串对象
boolean json = false; // 是否是JSON对象
String hexValue;
final StringBuilder builder = new StringBuilder();
do {
value = content.charAt(index.get());
if(value == JSON_STRING) {
if(string) {
string = false;
} else {
string = true;
}
} else if(value == JSON_MAP_PREFIX || value == JSON_LIST_PREFIX) {
json = true;
} else if(value == JSON_MAP_SUFFIX || value == JSON_LIST_SUFFIX) {
json = false;
}
// 不属于JSON对象和字符串对象出现分隔符:结束循环
if(!string && !json && (value == JSON_KV || value == JSON_ATTR)) {
index.incrementAndGet();
break;
}
if (value == '\\') { // 转义:参考{@link #BYTES}
index.incrementAndGet();
value = content.charAt(index.get());
switch (value) {
case 'b':
builder.append('\b');
break;
case 't':
builder.append('\t');
break;
case 'n':
builder.append('\n');
break;
case 'f':
builder.append('\f');
break;
case 'r':
builder.append('\r');
break;
case '"':
builder.append(value);
break;
case '\\':
builder.append(value);
break;
case 'u': // Unicode
hexValue = content.substring(index.get() + 1, index.get() + 5);
builder.append((char) Integer.parseInt(hexValue, 16));
index.addAndGet(4);
break;
default:
builder.append(value);
LOGGER.warn("不支持的JSON转义符号:{}", value);
break;
}
} else {
builder.append(value);
}
} while (index.incrementAndGet() < content.length());
return convertValue(builder.toString());
}
/**
* 类型转换
*/
private Object convertValue(String content) {
final String value = content.trim();
final int length = value.length();
if(
length > 1 &&
value.charAt(0) == JSON_STRING &&
value.charAt(value.length() - 1) == JSON_STRING
) { // 字符串
return value.substring(1, length - 1); // 去掉引号
} else if(
JSON_BOOLEAN_TRUE.equals(value) ||
JSON_BOOLEAN_FALSE.equals(value)
) { // Boolean
return Boolean.valueOf(value);
} else if(JSON_NULL.equals(value)) { // null
return null;
} else if(StringUtils.isDecimal(value)) { // 数字
return Integer.valueOf(value);
} else if(
length > 1 &&
value.charAt(0) == JSON_MAP_PREFIX && value.charAt(length - 1) == JSON_MAP_SUFFIX
) { // MAP:懒加载
// return JSON.ofString(value);
return value;
} else if(
length > 1 &&
value.charAt(0) == JSON_LIST_PREFIX && value.charAt(length - 1) == JSON_LIST_SUFFIX
) { // LIST:懒加载
// return JSON.ofString(value);
return value;
} else {
throw new ArgumentException("JSON格式错误:" + value);
}
}
public JSON getJSON(Object key) {
final Object value = get(key);
if(value == null) {
return null;
} else if(value instanceof JSON) {
return (JSON) value;
} else if(value instanceof String) {
return JSON.ofString((String) value);
} else {
throw new ArgumentException("JSON转换错误:" + value);
}
}
public List getList() {
return this.list;
}
public Integer getInteger(Object key) {
return (Integer) this.get(key);
}
public Boolean getBoolean(Object key) {
return (Boolean) this.get(key);
}
public String getString(Object key) {
return (String) this.get(key);
}
public Object get(Object key) {
return this.map.get(key);
}
public String toJSON() {
return this.serialize();
}
@Override
public String toString() {
return this.serialize();
}
}