This commit is contained in:
Looly 2024-09-27 20:13:19 +08:00
parent f2c379ee37
commit eecbf6ea29
13 changed files with 149 additions and 95 deletions

View File

@ -62,6 +62,22 @@ public final class InternalJSONUtil {
return Boolean.FALSE;
}
return parseNumberOrString(string);
}
/**
* 尝试转换字符串为number or null无法转换返回String<br>
* 此方法用于解析JSON字符串时将字符串中的值转换为JSON值对象
*
* @param string A String.
* @return A simple JSON value.
*/
public static Object parseNumberOrString(final String string) {
// null处理
if (StrUtil.isEmpty(string)) {
return null;
}
// Number处理
final char b = string.charAt(0);
if ((b >= '0' && b <= '9') || b == '-') {
@ -83,7 +99,8 @@ public final class InternalJSONUtil {
}
}
// 其它情况返回原String值下
// 无法解析的超大数字直接返回字符串
// "xxx"这种直接字符串形式的值直接返回
return string;
}

View File

@ -155,7 +155,7 @@ public class JSONFactory {
* @return {@link JSONParser}
*/
public JSONParser ofParser(final JSONTokener tokener){
return JSONParser.of(tokener, this.config).setPredicate(this.predicate);
return JSONParser.of(tokener, this);
}
/**

View File

@ -201,6 +201,11 @@ public class JSONPrimitive implements Wrapper<Object>, JSON {
}
}
@Override
public String toString() {
return toJSONString(0);
}
/**
* 写出数字根据{@link JSONConfig#isStripTrailingZeros()} 配置不同写出不同数字<br>
* 主要针对Double型是否去掉小数点后多余的0<br>

View File

@ -16,10 +16,10 @@
package org.dromara.hutool.json.engine;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.JSONConfig;
import org.dromara.hutool.json.JSONFactory;
import org.dromara.hutool.json.JSONUtil;
import java.io.Reader;
import java.io.Writer;
@ -39,7 +39,8 @@ public class HutoolJSONEngine extends AbstractJSONEngine {
public void serialize(final Object bean, final Writer writer) {
initEngine();
final JSON json = jsonFactory.parse(bean);
json.write(jsonFactory.ofWriter(writer, this.config.isPrettyPrint()));
json.write(jsonFactory.ofWriter(writer,
ObjUtil.defaultIfNull(this.config, JSONEngineConfig::isPrettyPrint, false)));
}
@Override

View File

@ -40,33 +40,25 @@ public class JSONParser {
* 创建JSONParser
*
* @param tokener {@link JSONTokener}
* @param config JSON配置
* @param factory JSON工厂
* @return JSONParser
*/
public static JSONParser of(final JSONTokener tokener, final JSONConfig config) {
return new JSONParser(tokener, config);
public static JSONParser of(final JSONTokener tokener, final JSONFactory factory) {
return new JSONParser(tokener, factory);
}
/**
* JSON配置
*/
private final JSONConfig config;
private final JSONTokener tokener;
/**
* 过滤器用于过滤或修改键值对返回null表示忽略此键值对返回非null表示修改后返回<br>
* entry中key在JSONObject中为name在JSONArray中为index
*/
private Predicate<MutableEntry<Object, Object>> predicate;
private final JSONFactory factory;
/**
* 构造
*
* @param tokener {@link JSONTokener}
* @param config JSON配置
* @param factory JSON工厂
*/
public JSONParser(final JSONTokener tokener, final JSONConfig config) {
public JSONParser(final JSONTokener tokener, final JSONFactory factory) {
this.tokener = tokener;
this.config = config;
this.factory = factory;
}
/**
@ -78,17 +70,6 @@ public class JSONParser {
return this.tokener;
}
/**
* 设置过滤器用于过滤或修改键值对返回null表示忽略此键值对返回非null表示修改后返回
*
* @param predicate 过滤器用于过滤或修改键值对返回null表示忽略此键值对返回非null表示修改后返回
* @return this
*/
public JSONParser setPredicate(final Predicate<MutableEntry<Object, Object>> predicate) {
this.predicate = predicate;
return this;
}
/**
* 获取下一个值可以是
* <pre>
@ -116,7 +97,7 @@ public class JSONParser {
* @param json JSON对象或数组用于存储解析结果
*/
public void parseTo(final JSON json) {
if(null == json){
if (null == json) {
return;
}
switch (tokener.nextClean()) {
@ -146,12 +127,12 @@ public class JSONParser {
final JSON result;
switch (firstChar) {
case CharUtil.DELIM_START:
final JSONObject jsonObject = new JSONObject(config);
final JSONObject jsonObject = factory.ofObj();
nextTo(jsonObject);
result = jsonObject;
break;
case CharUtil.BRACKET_START:
final JSONArray jsonArray = new JSONArray(config);
final JSONArray jsonArray = factory.ofArray();
nextTo(jsonArray);
result = jsonArray;
break;
@ -187,6 +168,7 @@ public class JSONParser {
// 过滤并设置键值对
final JSON value = nextJSON(tokener.nextClean());
// 添加前置过滤通过MutablePair实现过滤修改键值对等
final Predicate<MutableEntry<Object, Object>> predicate = factory.getPredicate();
if (null != predicate) {
final MutableEntry<Object, Object> entry = new MutableEntry<>(key, value);
if (predicate.test(entry)) {
@ -194,7 +176,7 @@ public class JSONParser {
key = (String) entry.getKey();
jsonObject.set(key, entry.getValue());
}
}else {
} else {
jsonObject.set(key, value);
}
@ -233,6 +215,7 @@ public class JSONParser {
} else {
// ,value or value
JSON value = nextJSON(CharUtil.COMMA == c ? tokener.nextClean() : c);
final Predicate<MutableEntry<Object, Object>> predicate = factory.getPredicate();
if (null != predicate) {
// 使用过滤器
final MutableEntry<Object, Object> entry = MutableEntry.of(jsonArray.size(), value);
@ -264,11 +247,72 @@ public class JSONParser {
case CharUtil.DOUBLE_QUOTES:
case CharUtil.SINGLE_QUOTE:
// 引号包围表示字符串值
return new JSONPrimitive(tokener.nextWrapString(firstChar), config);
return factory.ofPrimitive(tokener.nextWrapString(firstChar));
case 't':
case 'T':
checkTrue(tokener.next(3));
return factory.ofPrimitive(true);
case 'f':
case 'F':
checkFalse(tokener.next(4));
return factory.ofPrimitive(false);
case 'n':
case 'N':
checkNull(tokener.next(3));
return null;
default:
final Object value = InternalJSONUtil.parseValueFromString(tokener.nextUnwrapString(firstChar));
// 非引号包围可能为boolean数字null等
return null == value ? null : new JSONPrimitive(value, config);
final Object value = InternalJSONUtil.parseNumberOrString(tokener.nextUnwrapString(firstChar));
// 非引号包围可能为数字null等
return null == value ? null : factory.ofPrimitive(value);
}
}
/**
* 检查是否为true的rue部分
*
* @param next
*/
private void checkTrue(final char[] next) {
if ((next[0] == 'r' || next[0] == 'R') &&
(next[1] == 'u' || next[1] == 'U') &&
(next[2] == 'e' || next[2] == 'E')
) {
return;
}
throw tokener.syntaxError("Expected true but : t" + String.valueOf(next));
}
/**
* 检查是否为false的alse部分
*
* @param next
*/
private void checkFalse(final char[] next) {
if ((next[0] == 'a' || next[0] == 'A') &&
(next[1] == 'l' || next[1] == 'L') &&
(next[2] == 's' || next[2] == 'S') &&
(next[3] == 'e' || next[3] == 'E')
) {
return;
}
throw tokener.syntaxError("Expected false but : f" + String.valueOf(next));
}
/**
* 检查是否为null的ull部分
*
* @param next
*/
private void checkNull(final char[] next) {
if ((next[0] == 'u' || next[0] == 'U') &&
(next[1] == 'l' || next[1] == 'L') &&
(next[2] == 'l' || next[2] == 'L')
) {
return;
}
throw tokener.syntaxError("Expected null but : n" + String.valueOf(next));
}
}

View File

@ -16,7 +16,6 @@
package org.dromara.hutool.json.serializer;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.json.*;
/**
@ -35,13 +34,20 @@ public interface JSONContext {
*/
JSON getContextJson();
/**
* 获取JSON工厂
*
* @return JSON工厂
*/
JSONFactory getFactory();
/**
* 获取JSON配置
*
* @return JSON配置
*/
default JSONConfig config() {
return ObjUtil.apply(getContextJson(), JSON::config);
return getFactory().getConfig();
}
/**
@ -55,7 +61,7 @@ public interface JSONContext {
return (JSONObject) contextJson;
}
return JSONUtil.ofObj(config());
return getFactory().ofObj();
}
/**
@ -68,7 +74,7 @@ public interface JSONContext {
if (contextJson instanceof JSONArray) {
return (JSONArray) contextJson;
}
return JSONUtil.ofArray(config());
return getFactory().ofArray();
}
/**
@ -82,6 +88,6 @@ public interface JSONContext {
if (contextJson instanceof JSONPrimitive) {
return ((JSONPrimitive) contextJson).setValue(value);
}
return JSONUtil.ofPrimitive(value, config());
return getFactory().ofPrimitive(value);
}
}

View File

@ -286,7 +286,7 @@ public class JSONMapper implements Serializable {
final JSON result;
try {
result = serializer.serialize(obj, new SimpleJSONContext(json, this.factory.getConfig()));
result = serializer.serialize(obj, new SimpleJSONContext(json, this.factory));
} catch (final Exception e) {
if (ignoreError) {
return null;

View File

@ -16,9 +16,8 @@
package org.dromara.hutool.json.serializer;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.JSONConfig;
import org.dromara.hutool.json.JSONFactory;
/**
* 简单的JSON上下文用于在JSON序列化时提供配置项
@ -28,36 +27,27 @@ import org.dromara.hutool.json.JSONConfig;
*/
public class SimpleJSONContext implements JSONContext {
private final JSON json;
private final JSONConfig config;
private final JSON contextJson;
private final JSONFactory factory;
/**
* 构造
*
* @param json JSON对象
* @param contextJson JSON对象
* @param factory 配置项
*/
public SimpleJSONContext(final JSON json) {
this(Assert.notNull(json), json.config());
}
/**
* 构造
*
* @param json JSON对象
* @param config 配置项
*/
public SimpleJSONContext(final JSON json, final JSONConfig config) {
this.json = json;
this.config = config;
public SimpleJSONContext(final JSON contextJson, final JSONFactory factory) {
this.contextJson = contextJson;
this.factory = factory;
}
@Override
public JSON getContextJson() {
return this.json;
return this.contextJson;
}
@Override
public JSONConfig config() {
return this.config;
public JSONFactory getFactory() {
return factory;
}
}

View File

@ -20,8 +20,9 @@ import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.collection.iter.ArrayIter;
import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.reflect.TypeUtil;
import org.dromara.hutool.json.*;
import org.dromara.hutool.json.reader.JSONParser;
import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.JSONArray;
import org.dromara.hutool.json.JSONObject;
import org.dromara.hutool.json.reader.JSONTokener;
import org.dromara.hutool.json.serializer.JSONContext;
import org.dromara.hutool.json.serializer.MatcherJSONDeserializer;
@ -96,12 +97,11 @@ public class ArrayTypeAdapter implements MatcherJSONSerializer<Object>, MatcherJ
* @return JSONArray
*/
private JSON serializeBytes(final byte[] bytes, final JSONContext context) {
final JSONConfig config = context.config();
if(ArrayUtil.isNotEmpty(bytes)){
switch (bytes[0]) {
case '{':
case '[':
return JSONParser.of(new JSONTokener(IoUtil.toStream(bytes)), config).parse();
return context.getFactory().ofParser(new JSONTokener(IoUtil.toStream(bytes))).parse();
}
}

View File

@ -18,8 +18,9 @@ package org.dromara.hutool.json.serializer.impl;
import org.dromara.hutool.core.reflect.TypeUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.json.*;
import org.dromara.hutool.json.reader.JSONParser;
import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.JSONObject;
import org.dromara.hutool.json.JSONPrimitive;
import org.dromara.hutool.json.reader.JSONTokener;
import org.dromara.hutool.json.serializer.JSONContext;
import org.dromara.hutool.json.serializer.MatcherJSONDeserializer;
@ -62,7 +63,7 @@ public class CharSequenceTypeAdapter implements MatcherJSONSerializer<CharSequen
return jsonObject;
}
return mapFromTokener(new JSONTokener(jsonStr), context.config());
return context.getFactory().ofParser(new JSONTokener(jsonStr)).parse();
}
@Override
@ -72,14 +73,4 @@ public class CharSequenceTypeAdapter implements MatcherJSONSerializer<CharSequen
}
return json.toString();
}
/**
* {@link JSONTokener} 中读取JSON字符串并转换为JSON
*
* @param tokener {@link JSONTokener}
* @return JSON
*/
private JSON mapFromTokener(final JSONTokener tokener, final JSONConfig config) {
return JSONParser.of(tokener, config).setPredicate(null).parse();
}
}

View File

@ -18,7 +18,7 @@ package org.dromara.hutool.json.serializer.impl;
import org.dromara.hutool.core.io.resource.Resource;
import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.JSONConfig;
import org.dromara.hutool.json.JSONFactory;
import org.dromara.hutool.json.reader.JSONParser;
import org.dromara.hutool.json.reader.JSONTokener;
import org.dromara.hutool.json.serializer.JSONContext;
@ -44,7 +44,7 @@ public class ResourceSerializer implements MatcherJSONSerializer<Resource> {
@Override
public JSON serialize(final Resource bean, final JSONContext context) {
return mapFromTokener(new JSONTokener(bean.getStream()), context.config());
return context.getFactory().ofParser(new JSONTokener(bean.getStream())).parse();
}
/**
@ -53,7 +53,7 @@ public class ResourceSerializer implements MatcherJSONSerializer<Resource> {
* @param tokener {@link JSONTokener}
* @return JSON
*/
private JSON mapFromTokener(final JSONTokener tokener, final JSONConfig config) {
return JSONParser.of(tokener, config).setPredicate(null).parse();
private JSON mapFromTokener(final JSONTokener tokener, final JSONFactory factory) {
return JSONParser.of(tokener, factory).parse();
}
}

View File

@ -17,7 +17,7 @@
package org.dromara.hutool.json.serializer.impl;
import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.JSONConfig;
import org.dromara.hutool.json.JSONFactory;
import org.dromara.hutool.json.reader.JSONParser;
import org.dromara.hutool.json.reader.JSONTokener;
import org.dromara.hutool.json.serializer.JSONContext;
@ -49,13 +49,13 @@ public class TokenerSerializer implements MatcherJSONSerializer<Object> {
public JSON serialize(final Object bean, final JSONContext context) {
// 读取JSON流
if (bean instanceof JSONTokener) {
return mapFromTokener((JSONTokener) bean, context.config());
return mapFromTokener((JSONTokener) bean, context.getFactory());
} else if (bean instanceof JSONParser) {
return ((JSONParser) bean).parse();
} else if (bean instanceof Reader) {
return mapFromTokener(new JSONTokener((Reader) bean), context.config());
return mapFromTokener(new JSONTokener((Reader) bean), context.getFactory());
} else if (bean instanceof InputStream) {
return mapFromTokener(new JSONTokener((InputStream) bean), context.config());
return mapFromTokener(new JSONTokener((InputStream) bean), context.getFactory());
}
throw new IllegalArgumentException("Unsupported source: " + bean);
@ -67,7 +67,7 @@ public class TokenerSerializer implements MatcherJSONSerializer<Object> {
* @param tokener {@link JSONTokener}
* @return JSON
*/
private JSON mapFromTokener(final JSONTokener tokener, final JSONConfig config) {
return JSONParser.of(tokener, config).setPredicate(null).parse();
private JSON mapFromTokener(final JSONTokener tokener, final JSONFactory factory) {
return factory.ofParser(tokener).parse();
}
}

View File

@ -24,7 +24,7 @@ public class JSONParserTest {
@Test
void parseTest() {
final String jsonStr = " {\"a\": 1} ";
final JSONParser jsonParser = JSONParser.of(new JSONTokener(jsonStr), JSONConfig.of());
final JSONParser jsonParser = JSONParser.of(new JSONTokener(jsonStr), JSONFactory.getInstance());
final JSON parse = jsonParser.parse();
Assertions.assertEquals("{\"a\":1}", parse.toString());
}
@ -34,14 +34,14 @@ public class JSONParserTest {
final String jsonStr = "{\"a\": 1}";
final JSONObject jsonObject = JSONUtil.ofObj();
JSONParser.of(new JSONTokener(jsonStr), JSONConfig.of()).parseTo(jsonObject);
JSONParser.of(new JSONTokener(jsonStr), JSONFactory.getInstance()).parseTo(jsonObject);
Assertions.assertEquals("{\"a\":1}", jsonObject.toString());
}
@Test
void parseToArrayTest() {
final String jsonStr = "[{},2,3]";
final JSONParser jsonParser = JSONParser.of(new JSONTokener(jsonStr), JSONConfig.of());
final JSONParser jsonParser = JSONParser.of(new JSONTokener(jsonStr), JSONFactory.getInstance());
final JSONArray jsonArray = new JSONArray();
jsonParser.parseTo(jsonArray);