This commit is contained in:
Looly 2024-09-14 02:27:08 +08:00
parent 70b4f773e4
commit 7d3b614235
9 changed files with 176 additions and 178 deletions

View File

@ -32,8 +32,6 @@ import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.json.reader.JSONTokener;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Predicate;
@ -210,7 +208,7 @@ public final class InternalJSONUtil {
* @since 3.3.1
*/
public static String quote(final CharSequence string, final boolean isWrap) {
return quote(string, new StringWriter(), isWrap).toString();
return quote(string, new StringBuilder(), isWrap).toString();
}
/**
@ -219,11 +217,11 @@ public final class InternalJSONUtil {
* JSON字符串中不能包含控制字符和未经转义的引号和反斜杠
*
* @param str 字符串
* @param writer Writer
* @param appendable {@link Appendable}
* @throws IORuntimeException IO异常
*/
public static void quote(final CharSequence str, final Writer writer) throws IORuntimeException {
quote(str, writer, true);
public static void quote(final CharSequence str, final Appendable appendable) throws IORuntimeException {
quote(str, appendable, true);
}
/**
@ -232,15 +230,15 @@ public final class InternalJSONUtil {
* JSON字符串中不能包含控制字符和未经转义的引号和反斜杠
*
* @param str 字符串
* @param writer Writer
* @param appendable {@link Appendable}
* @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 {
public static Appendable quote(final CharSequence str, final Appendable appendable, final boolean isWrap) throws IORuntimeException {
try {
return _quote(str, writer, isWrap);
return _quote(str, appendable, isWrap);
} catch (final IOException e) {
throw new IORuntimeException(e);
}
@ -337,10 +335,10 @@ public final class InternalJSONUtil {
* @throws IOException IO异常
* @since 3.3.1
*/
private static Writer _quote(final CharSequence str, final Writer writer, final boolean isWrap) throws IOException {
private static Appendable _quote(final CharSequence str, final Appendable writer, final boolean isWrap) throws IOException {
if (StrUtil.isEmpty(str)) {
if (isWrap) {
writer.write("\"\"");
writer.append("\"\"");
}
return writer;
}
@ -348,22 +346,22 @@ public final class InternalJSONUtil {
char c; // 当前字符
final int len = str.length();
if (isWrap) {
writer.write('"');
writer.append('"');
}
for (int i = 0; i < len; i++) {
c = str.charAt(i);
switch (c) {
case '\\':
case '"':
writer.write("\\");
writer.write(c);
writer.append("\\");
writer.append(c);
break;
default:
writer.write(escape(c));
writer.append(escape(c));
}
}
if (isWrap) {
writer.write('"');
writer.append('"');
}
return writer;
}

View File

@ -19,14 +19,11 @@ package org.dromara.hutool.json;
import org.dromara.hutool.core.bean.path.BeanPath;
import org.dromara.hutool.core.convert.ConvertException;
import org.dromara.hutool.core.convert.Converter;
import org.dromara.hutool.core.lang.mutable.MutableEntry;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.json.writer.JSONWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Type;
import java.util.function.Predicate;
/**
* JSON树模型接口表示树中的一个节点实现包括
@ -155,20 +152,9 @@ public interface JSON extends Converter, Cloneable, Serializable {
* @throws JSONException 包含非法数抛出此异常
*/
default String toJSONString(final int indentFactor) throws JSONException {
final StringWriter sw = new StringWriter();
return this.write(sw, indentFactor, 0, null).toString();
}
/**
* 将JSON内容写入Writer无缩进<br>
* Warning: This method assumes that the data structure is acyclical.
*
* @param writer Writer
* @return Writer
* @throws JSONException JSON相关异常
*/
default Writer write(final Writer writer) throws JSONException {
return this.write(writer, 0, 0, null);
final JSONWriter jsonWriter = JSONWriter.of(new StringBuilder(), indentFactor, 0, config());
this.write(jsonWriter);
return jsonWriter.toString();
}
/**
@ -176,13 +162,9 @@ public interface JSON extends Converter, Cloneable, Serializable {
* Warning: This method assumes that the data structure is acyclical.
*
* @param writer writer
* @param indentFactor 缩进因子定义每一级别增加的缩进量
* @param indent 本级别缩进量
* @param predicate 过滤器可以修改值keyindex无法修改{@link Predicate#test(Object)}{@code true}保留
* @return Writer
* @throws JSONException JSON相关异常
*/
Writer write(Writer writer, int indentFactor, int indent, final Predicate<MutableEntry<Object, Object>> predicate) throws JSONException;
void write(JSONWriter writer) throws JSONException;
/**
* 转为实体类对象

View File

@ -29,8 +29,6 @@ import org.dromara.hutool.json.mapper.JSONArrayMapper;
import org.dromara.hutool.json.mapper.JSONValueMapper;
import org.dromara.hutool.json.writer.JSONWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.*;
import java.util.function.Predicate;
@ -564,20 +562,17 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
* @since 5.7.15
*/
public String toJSONString(final int indentFactor, final Predicate<MutableEntry<Object, Object>> predicate) {
final StringWriter sw = new StringWriter();
synchronized (sw.getBuffer()) {
return this.write(sw, indentFactor, 0, predicate).toString();
}
final JSONWriter jsonWriter = JSONWriter.of(new StringBuilder(), indentFactor, 0, this.config).setPredicate(predicate);
this.write(jsonWriter);
return jsonWriter.toString();
}
@Override
public Writer write(final Writer writer, final int indentFactor, final int indent, final Predicate<MutableEntry<Object, Object>> predicate) throws JSONException {
final JSONWriter jsonWriter = JSONWriter.of(writer, indentFactor, indent, config).beginArray();
CollUtil.forEach(this, (value, index) -> jsonWriter.writeField(new MutableEntry<>(index, value), predicate));
jsonWriter.end();
// 此处不关闭Writer考虑writer后续还需要填内容
return writer;
public void write(final JSONWriter writer) throws JSONException {
final JSONWriter copyWriter = writer.copyOf();
copyWriter.beginArray();
CollUtil.forEach(this, (value, index) -> copyWriter.writeField(new MutableEntry<>(index, value)));
copyWriter.end();
}
@Override

View File

@ -22,9 +22,6 @@ import org.dromara.hutool.core.map.MapWrapper;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.json.writer.JSONWriter;
import java.io.Writer;
import java.util.function.Predicate;
public class JSONObject extends MapWrapper<String, JSON> implements JSON{
/**
@ -71,12 +68,9 @@ public class JSONObject extends MapWrapper<String, JSON> implements JSON{
}
@Override
public Writer write(final Writer writer, final int indentFactor, final int indent, final Predicate<MutableEntry<Object, Object>> predicate) throws JSONException {
final JSONWriter jsonWriter = JSONWriter.of(writer, indentFactor, indent, config)
.beginObj();
this.forEach((key, value) -> jsonWriter.writeField(new MutableEntry<>(key, value), predicate));
jsonWriter.end();
// 此处不关闭Writer考虑writer后续还需要填内容
return writer;
public void write(final JSONWriter writer) throws JSONException {
writer.beginObj();
this.forEach((key, value) -> writer.writeField(new MutableEntry<>(key, value)));
writer.end();
}
}

View File

@ -17,15 +17,11 @@
package org.dromara.hutool.json;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.lang.mutable.MutableEntry;
import org.dromara.hutool.json.writer.JSONWriter;
import org.dromara.hutool.json.writer.ValueWriter;
import org.dromara.hutool.json.writer.ValueWriterManager;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Type;
import java.util.function.Predicate;
/**
* JSON原始类型数据封装根据RFC8259规范JSONPrimitive只包含以下类型
@ -114,25 +110,22 @@ public class JSONPrimitive implements JSON {
}
@Override
public Writer write(final Writer writer, final int indentFactor, final int indent, final Predicate<MutableEntry<Object, Object>> predicate) throws JSONException {
final Object value = this.value;
final JSONWriter jsonWriter = JSONWriter.of(writer, indentFactor, indent, config);
public void write(final JSONWriter writer) throws JSONException {
// 自定义规则
final ValueWriter valueWriter = ValueWriterManager.getInstance().get(value);
if (null != valueWriter) {
valueWriter.write(jsonWriter, value);
return writer;
valueWriter.write(writer, value);
return;
}
// 默认包装字符串
jsonWriter.writeQuoteStrValue(value.toString());
return writer;
writer.writeQuoteStrValue(value.toString());
}
@Override
public String toString() {
final StringWriter sw = new StringWriter();
return this.write(sw, 0, 0, null).toString();
final JSONWriter jsonWriter = JSONWriter.of(new StringBuilder(), 0, 0, this.config);
write(jsonWriter);
return jsonWriter.toString();
}
}

View File

@ -285,7 +285,7 @@ public class JSONUtil {
*/
public static void toJsonStr(final Object obj, final Writer writer) {
if (null != obj) {
parse(obj).write(writer);
parse(obj).write(JSONWriter.of(writer, 0, 0, null));
}
}

View File

@ -29,8 +29,6 @@ import org.dromara.hutool.json.mapper.JSONObjectMapper;
import org.dromara.hutool.json.mapper.JSONValueMapper;
import org.dromara.hutool.json.writer.JSONWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
@ -436,32 +434,17 @@ public class OldJSONObject extends MapWrapper<String, Object> implements JSON, J
* @since 5.7.15
*/
public String toJSONString(final int indentFactor, final Predicate<MutableEntry<Object, Object>> predicate) {
final StringWriter sw = new StringWriter();
synchronized (sw.getBuffer()) {
return this.write(sw, indentFactor, 0, predicate).toString();
}
final JSONWriter jsonWriter = JSONWriter.of(new StringBuilder(), indentFactor, 0, config).setPredicate(predicate);
write(jsonWriter);
return jsonWriter.toString();
}
/**
* 将JSON内容写入Writer<br>
* 支持过滤器即选择哪些字段或值不写出
*
* @param writer writer
* @param indentFactor 缩进因子定义每一级别增加的缩进量
* @param indent 本级别缩进量
* @param predicate 过滤器同时可以修改编辑键和值
* @return Writer
* @throws JSONException JSON相关异常
* @since 5.7.15
*/
@Override
public Writer write(final Writer writer, final int indentFactor, final int indent, final Predicate<MutableEntry<Object, Object>> predicate) throws JSONException {
final JSONWriter jsonWriter = JSONWriter.of(writer, indentFactor, indent, config)
.beginObj();
this.forEach((key, value) -> jsonWriter.writeField(new MutableEntry<>(key, value), predicate));
jsonWriter.end();
// 此处不关闭Writer考虑writer后续还需要填内容
return writer;
public void write(final JSONWriter writer) throws JSONException {
final JSONWriter copyWriter = writer.copyOf();
copyWriter.beginObj();
this.forEach((key, value) -> copyWriter.writeField(new MutableEntry<>(key, value)));
copyWriter.end();
}
@Override

View File

@ -20,6 +20,7 @@ import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.JSONConfig;
import org.dromara.hutool.json.JSONUtil;
import org.dromara.hutool.json.writer.JSONWriter;
import java.io.Reader;
import java.io.Writer;
@ -39,7 +40,11 @@ public class HutoolJSONEngine extends AbstractJSONEngine {
public void serialize(final Object bean, final Writer writer) {
initEngine();
final JSON json = JSONUtil.parse(bean, this.hutoolSJONConfig);
json.write(writer, ObjUtil.defaultIfNull(this.config, JSONEngineConfig::isPrettyPrint, false) ? 2 : 0, 0, null);
final JSONWriter jsonWriter = JSONWriter.of(writer,
ObjUtil.defaultIfNull(this.config, JSONEngineConfig::isPrettyPrint, false) ? 2 : 0,
0,
this.hutoolSJONConfig);
json.write(jsonWriter);
}
@Override

View File

@ -25,6 +25,8 @@ import org.dromara.hutool.json.InternalJSONUtil;
import org.dromara.hutool.json.JSON;
import org.dromara.hutool.json.JSONConfig;
import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.io.Writer;
import java.util.function.Predicate;
@ -36,24 +38,40 @@ import java.util.function.Predicate;
* @author looly
* @since 5.7.3
*/
public class JSONWriter extends Writer {
public class JSONWriter implements Appendable, Flushable, Closeable {
/**
* 创建JSONWriter
*
* @param appendable {@link Appendable}
* @param indentFactor 缩进因子定义每一级别增加的缩进量
* @param indent 本级别缩进量
* @param config JSON选项
* @return JSONWriter
*/
public static JSONWriter of(final Appendable appendable, final int indentFactor, final int indent,
final JSONConfig config) {
return new JSONWriter(appendable, indentFactor, indent, config);
}
/**
* Writer
*/
private final Appendable appendable;
/**
* JSON选项
*/
private final JSONConfig config;
/**
* 缩进因子定义每一级别增加的缩进量
*/
private final int indentFactor;
/**
* 本级别缩进量
* 键值对过滤器用于修改键值对
*/
private final int indent;
/**
* Writer
*/
private final Writer writer;
/**
* JSON选项
*/
private final JSONConfig config;
private Predicate<MutableEntry<Object, Object>> predicate;
/**
* 写出当前值是否需要分隔符
@ -63,33 +81,35 @@ public class JSONWriter extends Writer {
* 是否为JSONArray模式
*/
private boolean arrayMode;
/**
* 创建JSONWriter
*
* @param writer {@link Writer}
* @param indentFactor 缩进因子定义每一级别增加的缩进量
* @param indent 本级别缩进量
* @param config JSON选项
* @return JSONWriter
* 本级别缩进量
*/
public static JSONWriter of(final Writer writer, final int indentFactor, final int indent, final JSONConfig config) {
return new JSONWriter(writer, indentFactor, indent, config);
}
private int indent;
/**
* 构造
*
* @param writer {@link Writer}
* @param appendable {@link Appendable}
* @param indentFactor 缩进因子定义每一级别增加的缩进量
* @param indent 本级别缩进量
* @param config JSON选项
*/
public JSONWriter(final Writer writer, final int indentFactor, final int indent, final JSONConfig config) {
this.writer = writer;
public JSONWriter(final Appendable appendable, final int indentFactor, final int indent, final JSONConfig config) {
this.appendable = appendable;
this.indentFactor = indentFactor;
this.indent = indent;
this.config = ObjUtil.defaultIfNull(config, JSONConfig.of());
this.config = ObjUtil.defaultIfNull(config, JSONConfig::of);
}
/**
* 设置键值对过滤器用于修改键值对
*
* @param predicate 键值对过滤器用于修改键值对
* @return this
*/
public JSONWriter setPredicate(final Predicate<MutableEntry<Object, Object>> predicate) {
this.predicate = predicate;
return this;
}
/**
@ -101,14 +121,26 @@ public class JSONWriter extends Writer {
return this.config;
}
/**
* 复制当前对象用于修改配置后写出
* @return JSONWriter
*/
@SuppressWarnings("resource")
public JSONWriter copyOf() {
return new JSONWriter(this.appendable, this.indentFactor, this.indent, this.config)
.setPredicate(this.predicate);
}
/**
* JSONObject写出开始默认写出"{"
*
* @return this
*/
@SuppressWarnings("resource")
public JSONWriter beginObj() {
//noinspection resource
writeRaw(CharUtil.DELIM_START);
append(CharUtil.DELIM_START);
arrayMode = false;
needSeparator = false;
return this;
}
@ -117,10 +149,11 @@ public class JSONWriter extends Writer {
*
* @return this
*/
@SuppressWarnings("resource")
public JSONWriter beginArray() {
//noinspection resource
writeRaw(CharUtil.BRACKET_START);
append(CharUtil.BRACKET_START);
arrayMode = true;
needSeparator = false;
return this;
}
@ -129,12 +162,11 @@ public class JSONWriter extends Writer {
*
* @return this
*/
@SuppressWarnings("resource")
public JSONWriter end() {
// 换行缩进
//noinspection resource
writeLF().writeSpace(indent);
//noinspection resource
writeRaw(arrayMode ? CharUtil.BRACKET_END : CharUtil.DELIM_END);
append(arrayMode ? CharUtil.BRACKET_END : CharUtil.DELIM_END);
flush();
arrayMode = false;
// 当前对象或数组结束当新的
@ -147,12 +179,11 @@ public class JSONWriter extends Writer {
* {@link #arrayMode} {@code true} key是数字此时不写出键只写值
*
* @param pair 键值对
* @param predicate 过滤修改器
* @return this
* @since 6.0.0
*/
@SuppressWarnings({"UnusedReturnValue", "resource"})
public JSONWriter writeField(final MutableEntry<Object, Object> pair, final Predicate<MutableEntry<Object, Object>> predicate) {
@SuppressWarnings("resource")
public JSONWriter writeField(final MutableEntry<Object, Object> pair) {
if (null == pair.getValue() && config.isIgnoreNullValue()) {
return this;
}
@ -169,7 +200,7 @@ public class JSONWriter extends Writer {
writeKey(StrUtil.toString(pair.getKey()));
}
return writeValueDirect(pair.getValue(), predicate);
return writeValueDirect(pair.getValue());
}
/**
@ -178,35 +209,36 @@ public class JSONWriter extends Writer {
* @param key 键名
* @return this
*/
@SuppressWarnings({"resource", "UnusedReturnValue"})
@SuppressWarnings("resource")
public JSONWriter writeKey(final String key) {
if (needSeparator) {
//noinspection resource
writeRaw(CharUtil.COMMA);
append(CharUtil.COMMA);
}
// 换行缩进
writeLF().writeSpace(indentFactor + indent);
return writeRaw(InternalJSONUtil.quote(key));
}
@SuppressWarnings({"SpellCheckingInspection", "NullableProblems"})
@Override
public void write(final char[] cbuf, final int off, final int len) throws IOException {
this.writer.write(cbuf, off, len);
}
@Override
public void flush() {
if (this.appendable instanceof Flushable) {
try {
this.writer.flush();
((Flushable) this.appendable).flush();
} catch (final IOException e) {
throw new IORuntimeException(e);
}
}
}
@Override
public void close() throws IOException {
this.writer.close();
if (this.appendable instanceof AutoCloseable) {
try {
((AutoCloseable) this.appendable).close();
} catch (final Exception e) {
throw new IOException(e);
}
}
}
/**
@ -218,7 +250,7 @@ public class JSONWriter extends Writer {
* @param csq 字符串
*/
public void writeQuoteStrValue(final String csq) {
InternalJSONUtil.quote(csq, writer);
InternalJSONUtil.quote(csq, this.appendable);
}
/**
@ -230,7 +262,7 @@ public class JSONWriter extends Writer {
if (indentFactor > 0) {
for (int i = 0; i < count; i++) {
//noinspection resource
writeRaw(CharUtil.SPACE);
append(CharUtil.SPACE);
}
}
}
@ -243,7 +275,7 @@ public class JSONWriter extends Writer {
public JSONWriter writeLF() {
if (indentFactor > 0) {
//noinspection resource
writeRaw(CharUtil.LF);
append(CharUtil.LF);
}
return this;
}
@ -256,68 +288,84 @@ public class JSONWriter extends Writer {
*/
public JSONWriter writeRaw(final String csq) {
try {
writer.append(csq);
this.appendable.append(csq);
} catch (final IOException e) {
throw new IORuntimeException(e);
}
return this;
}
/**
* 写入原始字符值不做任何处理
*
* @param c 字符
* @return this
*/
public JSONWriter writeRaw(final char c) {
@Override
public JSONWriter append(final char c) throws IORuntimeException {
try {
writer.write(c);
this.appendable.append(c);
} catch (final IOException e) {
throw new IORuntimeException(e);
}
return this;
}
@Override
public JSONWriter append(final CharSequence csq) throws IORuntimeException {
try {
this.appendable.append(csq);
} catch (final IOException e) {
throw new IORuntimeException(e);
}
return this;
}
@Override
public JSONWriter append(final CharSequence csq, final int start, final int end) throws IORuntimeException {
try {
this.appendable.append(csq, start, end);
} catch (final IOException e) {
throw new IORuntimeException(e);
}
return this;
}
@Override
public String toString() {
return this.appendable.toString();
}
// ------------------------------------------------------------------------------ Private methods
/**
* 写出值自动处理分隔符和缩进自动判断类型并根据不同类型写出特定格式的值
*
* @param value
* @param predicate 过滤修改器
* @return this
*/
private JSONWriter writeValueDirect(final Object value, final Predicate<MutableEntry<Object, Object>> predicate) {
private JSONWriter writeValueDirect(final Object value) {
if (arrayMode) {
if (needSeparator) {
//noinspection resource
writeRaw(CharUtil.COMMA);
append(CharUtil.COMMA);
}
// 换行缩进
//noinspection resource
writeLF().writeSpace(indentFactor + indent);
} else {
//noinspection resource
writeRaw(CharUtil.COLON).writeSpace(1);
append(CharUtil.COLON).writeSpace(1);
}
needSeparator = true;
return writeObjValue(value, predicate);
return writeObjValue(value);
}
/**
* 写出JSON的值根据值类型不同输出不同内容
*
* @param value
* @param predicate 过滤修改器
* @return this
*/
@SuppressWarnings("resource")
private JSONWriter writeObjValue(final Object value, final Predicate<MutableEntry<Object, Object>> predicate) {
final int indent = indentFactor + this.indent;
private JSONWriter writeObjValue(final Object value) {
// 自定义规则
final ValueWriter valueWriter = ValueWriterManager.getInstance().get(value);
if(null != valueWriter){
if (null != valueWriter) {
valueWriter.write(this, value);
return this;
}
@ -325,8 +373,8 @@ public class JSONWriter extends Writer {
// 默认规则
if (value == null) {
writeRaw(StrUtil.NULL);
}else if (value instanceof JSON) {
((JSON) value).write(writer, indentFactor, indent, predicate);
} else if (value instanceof JSON) {
((JSON) value).write(this);
} else {
writeQuoteStrValue(value.toString());
}