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 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处理 // Number处理
final char b = string.charAt(0); final char b = string.charAt(0);
if ((b >= '0' && b <= '9') || b == '-') { if ((b >= '0' && b <= '9') || b == '-') {
@ -83,7 +99,8 @@ public final class InternalJSONUtil {
} }
} }
// 其它情况返回原String值下 // 无法解析的超大数字直接返回字符串
// "xxx"这种直接字符串形式的值直接返回
return string; return string;
} }

View File

@ -155,7 +155,7 @@ public class JSONFactory {
* @return {@link JSONParser} * @return {@link JSONParser}
*/ */
public JSONParser ofParser(final JSONTokener tokener){ 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> * 写出数字根据{@link JSONConfig#isStripTrailingZeros()} 配置不同写出不同数字<br>
* 主要针对Double型是否去掉小数点后多余的0<br> * 主要针对Double型是否去掉小数点后多余的0<br>

View File

@ -16,10 +16,10 @@
package org.dromara.hutool.json.engine; package org.dromara.hutool.json.engine;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.json.JSON; import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.JSONConfig; import org.dromara.hutool.json.JSONConfig;
import org.dromara.hutool.json.JSONFactory; import org.dromara.hutool.json.JSONFactory;
import org.dromara.hutool.json.JSONUtil;
import java.io.Reader; import java.io.Reader;
import java.io.Writer; import java.io.Writer;
@ -39,7 +39,8 @@ public class HutoolJSONEngine extends AbstractJSONEngine {
public void serialize(final Object bean, final Writer writer) { public void serialize(final Object bean, final Writer writer) {
initEngine(); initEngine();
final JSON json = jsonFactory.parse(bean); 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 @Override

View File

@ -40,33 +40,25 @@ public class JSONParser {
* 创建JSONParser * 创建JSONParser
* *
* @param tokener {@link JSONTokener} * @param tokener {@link JSONTokener}
* @param config JSON配置 * @param factory JSON工厂
* @return JSONParser * @return JSONParser
*/ */
public static JSONParser of(final JSONTokener tokener, final JSONConfig config) { public static JSONParser of(final JSONTokener tokener, final JSONFactory factory) {
return new JSONParser(tokener, config); return new JSONParser(tokener, factory);
} }
/**
* JSON配置
*/
private final JSONConfig config;
private final JSONTokener tokener; private final JSONTokener tokener;
/** private final JSONFactory factory;
* 过滤器用于过滤或修改键值对返回null表示忽略此键值对返回非null表示修改后返回<br>
* entry中key在JSONObject中为name在JSONArray中为index
*/
private Predicate<MutableEntry<Object, Object>> predicate;
/** /**
* 构造 * 构造
* *
* @param tokener {@link JSONTokener} * @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.tokener = tokener;
this.config = config; this.factory = factory;
} }
/** /**
@ -78,17 +70,6 @@ public class JSONParser {
return this.tokener; 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> * <pre>
@ -116,7 +97,7 @@ public class JSONParser {
* @param json JSON对象或数组用于存储解析结果 * @param json JSON对象或数组用于存储解析结果
*/ */
public void parseTo(final JSON json) { public void parseTo(final JSON json) {
if(null == json){ if (null == json) {
return; return;
} }
switch (tokener.nextClean()) { switch (tokener.nextClean()) {
@ -146,12 +127,12 @@ public class JSONParser {
final JSON result; final JSON result;
switch (firstChar) { switch (firstChar) {
case CharUtil.DELIM_START: case CharUtil.DELIM_START:
final JSONObject jsonObject = new JSONObject(config); final JSONObject jsonObject = factory.ofObj();
nextTo(jsonObject); nextTo(jsonObject);
result = jsonObject; result = jsonObject;
break; break;
case CharUtil.BRACKET_START: case CharUtil.BRACKET_START:
final JSONArray jsonArray = new JSONArray(config); final JSONArray jsonArray = factory.ofArray();
nextTo(jsonArray); nextTo(jsonArray);
result = jsonArray; result = jsonArray;
break; break;
@ -187,6 +168,7 @@ public class JSONParser {
// 过滤并设置键值对 // 过滤并设置键值对
final JSON value = nextJSON(tokener.nextClean()); final JSON value = nextJSON(tokener.nextClean());
// 添加前置过滤通过MutablePair实现过滤修改键值对等 // 添加前置过滤通过MutablePair实现过滤修改键值对等
final Predicate<MutableEntry<Object, Object>> predicate = factory.getPredicate();
if (null != predicate) { if (null != predicate) {
final MutableEntry<Object, Object> entry = new MutableEntry<>(key, value); final MutableEntry<Object, Object> entry = new MutableEntry<>(key, value);
if (predicate.test(entry)) { if (predicate.test(entry)) {
@ -194,7 +176,7 @@ public class JSONParser {
key = (String) entry.getKey(); key = (String) entry.getKey();
jsonObject.set(key, entry.getValue()); jsonObject.set(key, entry.getValue());
} }
}else { } else {
jsonObject.set(key, value); jsonObject.set(key, value);
} }
@ -233,6 +215,7 @@ public class JSONParser {
} else { } else {
// ,value or value // ,value or value
JSON value = nextJSON(CharUtil.COMMA == c ? tokener.nextClean() : c); JSON value = nextJSON(CharUtil.COMMA == c ? tokener.nextClean() : c);
final Predicate<MutableEntry<Object, Object>> predicate = factory.getPredicate();
if (null != predicate) { if (null != predicate) {
// 使用过滤器 // 使用过滤器
final MutableEntry<Object, Object> entry = MutableEntry.of(jsonArray.size(), value); final MutableEntry<Object, Object> entry = MutableEntry.of(jsonArray.size(), value);
@ -264,11 +247,72 @@ public class JSONParser {
case CharUtil.DOUBLE_QUOTES: case CharUtil.DOUBLE_QUOTES:
case CharUtil.SINGLE_QUOTE: 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: default:
final Object value = InternalJSONUtil.parseValueFromString(tokener.nextUnwrapString(firstChar)); final Object value = InternalJSONUtil.parseNumberOrString(tokener.nextUnwrapString(firstChar));
// 非引号包围可能为boolean数字null等 // 非引号包围可能为数字null等
return null == value ? null : new JSONPrimitive(value, config); 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; package org.dromara.hutool.json.serializer;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.json.*; import org.dromara.hutool.json.*;
/** /**
@ -35,13 +34,20 @@ public interface JSONContext {
*/ */
JSON getContextJson(); JSON getContextJson();
/**
* 获取JSON工厂
*
* @return JSON工厂
*/
JSONFactory getFactory();
/** /**
* 获取JSON配置 * 获取JSON配置
* *
* @return JSON配置 * @return JSON配置
*/ */
default JSONConfig config() { default JSONConfig config() {
return ObjUtil.apply(getContextJson(), JSON::config); return getFactory().getConfig();
} }
/** /**
@ -55,7 +61,7 @@ public interface JSONContext {
return (JSONObject) contextJson; return (JSONObject) contextJson;
} }
return JSONUtil.ofObj(config()); return getFactory().ofObj();
} }
/** /**
@ -68,7 +74,7 @@ public interface JSONContext {
if (contextJson instanceof JSONArray) { if (contextJson instanceof JSONArray) {
return (JSONArray) contextJson; return (JSONArray) contextJson;
} }
return JSONUtil.ofArray(config()); return getFactory().ofArray();
} }
/** /**
@ -82,6 +88,6 @@ public interface JSONContext {
if (contextJson instanceof JSONPrimitive) { if (contextJson instanceof JSONPrimitive) {
return ((JSONPrimitive) contextJson).setValue(value); 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; final JSON result;
try { try {
result = serializer.serialize(obj, new SimpleJSONContext(json, this.factory.getConfig())); result = serializer.serialize(obj, new SimpleJSONContext(json, this.factory));
} catch (final Exception e) { } catch (final Exception e) {
if (ignoreError) { if (ignoreError) {
return null; return null;

View File

@ -16,9 +16,8 @@
package org.dromara.hutool.json.serializer; package org.dromara.hutool.json.serializer;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.json.JSON; import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.JSONConfig; import org.dromara.hutool.json.JSONFactory;
/** /**
* 简单的JSON上下文用于在JSON序列化时提供配置项 * 简单的JSON上下文用于在JSON序列化时提供配置项
@ -28,36 +27,27 @@ import org.dromara.hutool.json.JSONConfig;
*/ */
public class SimpleJSONContext implements JSONContext { public class SimpleJSONContext implements JSONContext {
private final JSON json; private final JSON contextJson;
private final JSONConfig config; private final JSONFactory factory;
/** /**
* 构造 * 构造
* *
* @param json JSON对象 * @param contextJson JSON对象
* @param factory 配置项
*/ */
public SimpleJSONContext(final JSON json) { public SimpleJSONContext(final JSON contextJson, final JSONFactory factory) {
this(Assert.notNull(json), json.config()); this.contextJson = contextJson;
} this.factory = factory;
/**
* 构造
*
* @param json JSON对象
* @param config 配置项
*/
public SimpleJSONContext(final JSON json, final JSONConfig config) {
this.json = json;
this.config = config;
} }
@Override @Override
public JSON getContextJson() { public JSON getContextJson() {
return this.json; return this.contextJson;
} }
@Override @Override
public JSONConfig config() { public JSONFactory getFactory() {
return this.config; 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.collection.iter.ArrayIter;
import org.dromara.hutool.core.io.IoUtil; import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.reflect.TypeUtil; import org.dromara.hutool.core.reflect.TypeUtil;
import org.dromara.hutool.json.*; import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.reader.JSONParser; import org.dromara.hutool.json.JSONArray;
import org.dromara.hutool.json.JSONObject;
import org.dromara.hutool.json.reader.JSONTokener; import org.dromara.hutool.json.reader.JSONTokener;
import org.dromara.hutool.json.serializer.JSONContext; import org.dromara.hutool.json.serializer.JSONContext;
import org.dromara.hutool.json.serializer.MatcherJSONDeserializer; import org.dromara.hutool.json.serializer.MatcherJSONDeserializer;
@ -96,12 +97,11 @@ public class ArrayTypeAdapter implements MatcherJSONSerializer<Object>, MatcherJ
* @return JSONArray * @return JSONArray
*/ */
private JSON serializeBytes(final byte[] bytes, final JSONContext context) { private JSON serializeBytes(final byte[] bytes, final JSONContext context) {
final JSONConfig config = context.config();
if(ArrayUtil.isNotEmpty(bytes)){ if(ArrayUtil.isNotEmpty(bytes)){
switch (bytes[0]) { switch (bytes[0]) {
case '{': case '{':
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.reflect.TypeUtil;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.json.*; import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.reader.JSONParser; import org.dromara.hutool.json.JSONObject;
import org.dromara.hutool.json.JSONPrimitive;
import org.dromara.hutool.json.reader.JSONTokener; import org.dromara.hutool.json.reader.JSONTokener;
import org.dromara.hutool.json.serializer.JSONContext; import org.dromara.hutool.json.serializer.JSONContext;
import org.dromara.hutool.json.serializer.MatcherJSONDeserializer; import org.dromara.hutool.json.serializer.MatcherJSONDeserializer;
@ -62,7 +63,7 @@ public class CharSequenceTypeAdapter implements MatcherJSONSerializer<CharSequen
return jsonObject; return jsonObject;
} }
return mapFromTokener(new JSONTokener(jsonStr), context.config()); return context.getFactory().ofParser(new JSONTokener(jsonStr)).parse();
} }
@Override @Override
@ -72,14 +73,4 @@ public class CharSequenceTypeAdapter implements MatcherJSONSerializer<CharSequen
} }
return json.toString(); 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.core.io.resource.Resource;
import org.dromara.hutool.json.JSON; 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.JSONParser;
import org.dromara.hutool.json.reader.JSONTokener; import org.dromara.hutool.json.reader.JSONTokener;
import org.dromara.hutool.json.serializer.JSONContext; import org.dromara.hutool.json.serializer.JSONContext;
@ -44,7 +44,7 @@ public class ResourceSerializer implements MatcherJSONSerializer<Resource> {
@Override @Override
public JSON serialize(final Resource bean, final JSONContext context) { 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} * @param tokener {@link JSONTokener}
* @return JSON * @return JSON
*/ */
private JSON mapFromTokener(final JSONTokener tokener, final JSONConfig config) { private JSON mapFromTokener(final JSONTokener tokener, final JSONFactory factory) {
return JSONParser.of(tokener, config).setPredicate(null).parse(); return JSONParser.of(tokener, factory).parse();
} }
} }

View File

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

View File

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