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

cn.hutool.json.serialize.JSONWriter Maven / Gradle / Ivy

Go to download

Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。

There is a newer version: 5.8.34
Show newest version
package cn.hutool.json.serialize;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TemporalAccessorUtil;
import cn.hutool.core.date.format.GlobalCustomFormat;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.lang.Filter;
import cn.hutool.core.lang.mutable.MutablePair;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONException;
import cn.hutool.json.JSONNull;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONString;
import cn.hutool.json.JSONUtil;

import java.io.IOException;
import java.io.Writer;
import java.time.MonthDay;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;

/**
 * JSON数据写出器
* 通过简单的append方式将JSON的键值对等信息写出到{@link Writer}中。 * * @author looly * @since 5.7.3 */ public class JSONWriter extends Writer { /** * 缩进因子,定义每一级别增加的缩进量 */ private final int indentFactor; /** * 本级别缩进量 */ private final int indent; /** * Writer */ private final Writer writer; /** * JSON选项 */ private final JSONConfig config; /** * 写出当前值是否需要分隔符 */ private boolean needSeparator; /** * 是否为JSONArray模式 */ private boolean arrayMode; /** * 创建JSONWriter * * @param writer {@link Writer} * @param indentFactor 缩进因子,定义每一级别增加的缩进量 * @param indent 本级别缩进量 * @param config JSON选项 * @return JSONWriter */ public static JSONWriter of(Writer writer, int indentFactor, int indent, JSONConfig config) { return new JSONWriter(writer, indentFactor, indent, config); } /** * 构造 * * @param writer {@link Writer} * @param indentFactor 缩进因子,定义每一级别增加的缩进量 * @param indent 本级别缩进量 * @param config JSON选项 */ public JSONWriter(Writer writer, int indentFactor, int indent, JSONConfig config) { this.writer = writer; this.indentFactor = indentFactor; this.indent = indent; this.config = config; } /** * JSONObject写出开始,默认写出"{" * * @return this */ public JSONWriter beginObj() { writeRaw(CharUtil.DELIM_START); return this; } /** * JSONArray写出开始,默认写出"[" * * @return this */ public JSONWriter beginArray() { writeRaw(CharUtil.BRACKET_START); arrayMode = true; return this; } /** * 结束,默认根据开始的类型,补充"}"或"]" * * @return this */ public JSONWriter end() { // 换行缩进 writeLF().writeSpace(indent); writeRaw(arrayMode ? CharUtil.BRACKET_END : CharUtil.DELIM_END); flush(); arrayMode = false; // 当前对象或数组结束,当新的 needSeparator = true; return this; } /** * 写出键,自动处理分隔符和缩进,并包装键名 * * @param key 键名 * @return this */ public JSONWriter writeKey(String key) { if (needSeparator) { writeRaw(CharUtil.COMMA); } // 换行缩进 writeLF().writeSpace(indentFactor + indent); return writeRaw(JSONUtil.quote(key)); } /** * 写出值,自动处理分隔符和缩进,自动判断类型,并根据不同类型写出特定格式的值
* 如果写出的值为{@code null}或者{@link JSONNull},且配置忽略null,则跳过。 * * @param value 值 * @return this */ public JSONWriter writeValue(Object value) { if(JSONUtil.isNull(value) && config.isIgnoreNullValue()){ return this; } return writeValueDirect(value, null); } /** * 写出字段名及字段值,如果字段值是{@code null}且忽略null值,则不写出任何内容 * * @param key 字段名 * @param value 字段值 * @return this * @since 5.7.6 * @deprecated 请使用 {@link #writeField(MutablePair, Filter)} */ @Deprecated public JSONWriter writeField(String key, Object value){ if(JSONUtil.isNull(value) && config.isIgnoreNullValue()){ return this; } return writeKey(key).writeValueDirect(value, null); } /** * 写出字段名及字段值,如果字段值是{@code null}且忽略null值,则不写出任何内容 * * @param pair 键值对 * @param filter 键值对的过滤器,可以编辑键值对 * @return this * @since 5.8.6 */ public JSONWriter writeField(MutablePair pair, Filter> filter){ if(JSONUtil.isNull(pair.getValue()) && config.isIgnoreNullValue()){ return this; } if (null == filter || filter.accept(pair)) { if(false == arrayMode){ // JSONArray只写值,JSONObject写键值对 writeKey(StrUtil.toString(pair.getKey())); } return writeValueDirect(pair.getValue(), filter); } return this; } @Override public void write(char[] cbuf, int off, int len) throws IOException { this.writer.write(cbuf, off, len); } @Override public void flush() { try { this.writer.flush(); } catch (IOException e) { throw new IORuntimeException(e); } } @Override public void close() throws IOException { this.writer.close(); } // ------------------------------------------------------------------------------ Private methods /** * 写出值,自动处理分隔符和缩进,自动判断类型,并根据不同类型写出特定格式的值 * * @param value 值 * @param filter 键值对过滤器 * @return this */ private JSONWriter writeValueDirect(Object value, Filter> filter) { if (arrayMode) { if (needSeparator) { writeRaw(CharUtil.COMMA); } // 换行缩进 writeLF().writeSpace(indentFactor + indent); } else { writeRaw(CharUtil.COLON).writeSpace(1); } needSeparator = true; return writeObjValue(value, filter); } /** * 写出JSON的值,根据值类型不同,输出不同内容 * * @param value 值 * @param filter 过滤器 * @return this */ private JSONWriter writeObjValue(Object value, Filter> filter) { final int indent = indentFactor + this.indent; if (value == null || value instanceof JSONNull) { writeRaw(JSONNull.NULL.toString()); } else if (value instanceof JSON) { if(value instanceof JSONObject){ ((JSONObject) value).write(writer, indentFactor, indent, filter); }else if(value instanceof JSONArray){ ((JSONArray) value).write(writer, indentFactor, indent, filter); } } else if (value instanceof Map || value instanceof Map.Entry) { new JSONObject(value).write(writer, indentFactor, indent); } else if (value instanceof Iterable || value instanceof Iterator || ArrayUtil.isArray(value)) { new JSONArray(value).write(writer, indentFactor, indent); } else if (value instanceof Number) { if(value instanceof Long && config.isWriteLongAsString()){ // issue#3541 // long可能溢出,此时可选是否将long写出为字符串类型 writeStrValue(value.toString()); } else { writeNumberValue((Number) value); } } else if (value instanceof Date || value instanceof Calendar || value instanceof TemporalAccessor) { // issue#2572@Github if(value instanceof MonthDay){ writeStrValue(value.toString()); return this; } final String format = (null == config) ? null : config.getDateFormat(); writeRaw(formatDate(value, format)); } else if (value instanceof Boolean) { writeBooleanValue((Boolean) value); } else if (value instanceof JSONString) { writeJSONStringValue((JSONString) value); } else { writeStrValue(value.toString()); } return this; } /** * 写出数字,根据{@link JSONConfig#isStripTrailingZeros()} 配置不同,写出不同数字
* 主要针对Double型是否去掉小数点后多余的0
* 此方法输出的值不包装引号。 * * @param number 数字 */ private void writeNumberValue(Number number) { // since 5.6.2可配置是否去除末尾多余0,例如如果为true,5.0返回5 final boolean isStripTrailingZeros = null == config || config.isStripTrailingZeros(); writeRaw(NumberUtil.toStr(number, isStripTrailingZeros)); } /** * 写出Boolean值,直接写出true或false,不适用引号包装 * * @param value Boolean值 */ private void writeBooleanValue(Boolean value) { writeRaw(value.toString()); } /** * 输出实现了{@link JSONString}接口的对象,通过调用{@link JSONString#toJSONString()}获取JSON字符串
* {@link JSONString}按照JSON对象对待,此方法输出的JSON字符串不包装引号。
* 如果toJSONString()返回null,调用toString()方法并使用双引号包装。 * * @param jsonString {@link JSONString} */ private void writeJSONStringValue(JSONString jsonString) { String valueStr; try { valueStr = jsonString.toJSONString(); } catch (Exception e) { throw new JSONException(e); } if (null != valueStr) { writeRaw(valueStr); } else { writeStrValue(jsonString.toString()); } } /** * 写出字符串值,并包装引号并转义字符
* 对所有双引号做转义处理(使用双反斜杠做转义)
* 为了能在HTML中较好的显示,会将</转义为<\/
* JSON字符串中不能包含控制字符和未经转义的引号和反斜杠 * * @param csq 字符串 */ private void writeStrValue(String csq) { try { JSONUtil.quote(csq, writer); } catch (IOException e) { throw new IORuntimeException(e); } } /** * 写出空格 * * @param count 空格数 */ private void writeSpace(int count) { if (indentFactor > 0) { for (int i = 0; i < count; i++) { writeRaw(CharUtil.SPACE); } } } /** * 写出换换行符 * * @return this */ private JSONWriter writeLF() { if (indentFactor > 0) { writeRaw(CharUtil.LF); } return this; } /** * 写入原始字符串值,不做任何处理 * * @param csq 字符串 * @return this */ private JSONWriter writeRaw(String csq) { try { writer.append(csq); } catch (IOException e) { throw new IORuntimeException(e); } return this; } /** * 写入原始字符值,不做任何处理 * * @param c 字符串 * @return this */ private JSONWriter writeRaw(char c) { try { writer.write(c); } catch (IOException e) { throw new IORuntimeException(e); } return this; } /** * 按照给定格式格式化日期,格式为空时返回时间戳字符串 * * @param dateObj Date或者Calendar对象 * @param format 格式 * @return 日期字符串 */ private static String formatDate(Object dateObj, String format) { if (StrUtil.isNotBlank(format)) { final String dateStr; if (dateObj instanceof TemporalAccessor) { dateStr = TemporalAccessorUtil.format((TemporalAccessor) dateObj, format); } else { dateStr = DateUtil.format(Convert.toDate(dateObj), format); } if (GlobalCustomFormat.FORMAT_SECONDS.equals(format) || GlobalCustomFormat.FORMAT_MILLISECONDS.equals(format)) { // Hutool自定义的秒和毫秒表示,默认不包装双引号 return dateStr; } //用户定义了日期格式 return JSONUtil.quote(dateStr); } //默认使用时间戳 long timeMillis; if (dateObj instanceof TemporalAccessor) { timeMillis = TemporalAccessorUtil.toEpochMilli((TemporalAccessor) dateObj); } else if (dateObj instanceof Date) { timeMillis = ((Date) dateObj).getTime(); } else if (dateObj instanceof Calendar) { timeMillis = ((Calendar) dateObj).getTimeInMillis(); } else { throw new UnsupportedOperationException("Unsupported Date type: " + dateObj.getClass()); } return String.valueOf(timeMillis); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy