remove JSONNull

This commit is contained in:
Looly 2022-06-07 11:55:28 +08:00
parent f985887406
commit c914574c30
16 changed files with 157 additions and 202 deletions

View File

@ -186,15 +186,13 @@ public class ObjUtil {
* *
* <pre> * <pre>
* 1. == null * 1. == null
* 2. equals(null)
* </pre> * </pre>
* *
* @param obj 对象 * @param obj 对象
* @return 是否为null * @return 是否为null
*/ */
public static boolean isNull(final Object obj) { public static boolean isNull(final Object obj) {
//noinspection ConstantConditions return null == obj;
return null == obj || obj.equals(null);
} }
/** /**

View File

@ -59,8 +59,8 @@ public final class InternalJSONUtil {
* @throws JSONException If the value is or contains an invalid number. * @throws JSONException If the value is or contains an invalid number.
*/ */
static String valueToString(final Object value) throws JSONException { static String valueToString(final Object value) throws JSONException {
if (value == null || value instanceof JSONNull) { if (value == null) {
return JSONNull.NULL.toString(); return StrUtil.NULL;
} }
if (value instanceof JSONString) { if (value instanceof JSONString) {
try { try {
@ -94,7 +94,7 @@ public final class InternalJSONUtil {
public static Object stringToValue(final String string) { public static Object stringToValue(final String string) {
// null处理 // null处理
if (StrUtil.isEmpty(string) || StrUtil.NULL.equalsIgnoreCase(string)) { if (StrUtil.isEmpty(string) || StrUtil.NULL.equalsIgnoreCase(string)) {
return JSONNull.NULL; return null;
} }
// boolean处理 // boolean处理

View File

@ -36,7 +36,9 @@ public interface JSON extends Cloneable, Serializable {
* @see BeanPath#get(Object) * @see BeanPath#get(Object)
* @since 4.0.6 * @since 4.0.6
*/ */
Object getByPath(String expression); default Object getByPath(String expression){
return BeanPath.of(expression).get(this);
}
/** /**
* 设置表达式指定位置或filed对应的值<br> * 设置表达式指定位置或filed对应的值<br>
@ -59,7 +61,9 @@ public interface JSON extends Cloneable, Serializable {
* @param expression 表达式 * @param expression 表达式
* @param value * @param value
*/ */
void putByPath(String expression, Object value); default void putByPath(String expression, Object value){
BeanPath.of(expression).set(this, value);
}
/** /**
* 通过表达式获取JSON中嵌套的对象<br> * 通过表达式获取JSON中嵌套的对象<br>

View File

@ -1,13 +1,12 @@
package cn.hutool.json; package cn.hutool.json;
import cn.hutool.core.bean.BeanPath;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.convert.impl.ArrayConverter; import cn.hutool.core.convert.impl.ArrayConverter;
import cn.hutool.core.lang.func.Filter; import cn.hutool.core.lang.func.Filter;
import cn.hutool.core.lang.mutable.Mutable; import cn.hutool.core.lang.mutable.Mutable;
import cn.hutool.core.lang.mutable.MutableObj;
import cn.hutool.core.lang.mutable.MutableEntry; import cn.hutool.core.lang.mutable.MutableEntry;
import cn.hutool.core.lang.mutable.MutableObj;
import cn.hutool.core.text.StrJoiner; import cn.hutool.core.text.StrJoiner;
import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.serialize.JSONWriter; import cn.hutool.json.serialize.JSONWriter;
@ -192,19 +191,9 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
return (index < 0 || index >= this.size()) ? defaultValue : this.rawList.get(index); return (index < 0 || index >= this.size()) ? defaultValue : this.rawList.get(index);
} }
@Override
public Object getByPath(final String expression) {
return BeanPath.of(expression).get(this);
}
@Override @Override
public <T> T getByPath(final String expression, final Class<T> resultType) { public <T> T getByPath(final String expression, final Class<T> resultType) {
return JSONConverter.jsonConvert(resultType, getByPath(expression), true); return JSONConverter.jsonConvert(resultType, getByPath(expression), this.config.isIgnoreError());
}
@Override
public void putByPath(final String expression, final Object value) {
BeanPath.of(expression).set(this, value);
} }
/** /**
@ -376,6 +365,9 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
} }
final ArrayList<Object> list = new ArrayList<>(c.size()); final ArrayList<Object> list = new ArrayList<>(c.size());
for (final Object object : c) { for (final Object object : c) {
if(null == object && config.isIgnoreNullValue()){
continue;
}
list.add(JSONUtil.wrap(object, this.config)); list.add(JSONUtil.wrap(object, this.config));
} }
return rawList.addAll(index, list); return rawList.addAll(index, list);
@ -428,25 +420,36 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
} }
} }
// 越界则追加到指定位置
if (index >= size()) { if (index >= size()) {
add(index, element); add(index, element);
return null;
}
if(null == element && config.isIgnoreNullValue()){
return null;
} }
return this.rawList.set(index, JSONUtil.wrap(element, this.config)); return this.rawList.set(index, JSONUtil.wrap(element, this.config));
} }
@Override @Override
public void add(final int index, final Object element) { public void add(int index, final Object element) {
if (index < 0) { if(null == element && config.isIgnoreNullValue()){
throw new JSONException("JSONArray[{}] not found.", index); return;
} }
if (index < this.size()) { if (index < this.size()) {
if (index < 0) {
index = 0;
}
InternalJSONUtil.testValidity(element); InternalJSONUtil.testValidity(element);
this.rawList.add(index, JSONUtil.wrap(element, this.config)); this.rawList.add(index, JSONUtil.wrap(element, this.config));
} else { } else {
while (index != this.size()) { if(false == config.isIgnoreNullValue()){
this.add(JSONNull.NULL); while (index != this.size()) {
// 非末尾则填充null
this.add(null);
}
} }
this.set(element); this.add(element);
} }
} }
@ -583,6 +586,10 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
return false; return false;
} }
} }
if(null == obj && config.isIgnoreNullValue()){
// 忽略空则不添加
return false;
}
return this.rawList.add(obj); return this.rawList.add(obj);
} }
} }

View File

@ -53,7 +53,7 @@ public class JSONConverter implements Converter {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected static <T> T jsonConvert(final Type targetType, final Object value, final boolean ignoreError) throws ConvertException { protected static <T> T jsonConvert(final Type targetType, final Object value, final boolean ignoreError) throws ConvertException {
if (JSONUtil.isNull(value)) { if (null == value) {
return null; return null;
} }
@ -91,7 +91,7 @@ public class JSONConverter implements Converter {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected static <T> T jsonToBean(final Type targetType, final Object value, final boolean ignoreError) throws ConvertException { protected static <T> T jsonToBean(final Type targetType, final Object value, final boolean ignoreError) throws ConvertException {
if (JSONUtil.isNull(value)) { if (null == value) {
return null; return null;
} }

View File

@ -6,6 +6,7 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.getter.OptNullBasicTypeFromObjectGetter; import cn.hutool.core.lang.getter.OptNullBasicTypeFromObjectGetter;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ObjUtil;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Date; import java.util.Date;
@ -32,10 +33,10 @@ public interface JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K> {
* key对应值是否为{@code null}或无此key * key对应值是否为{@code null}或无此key
* *
* @param key * @param key
* @return true 无此key或值为{@code null}{@link JSONNull#NULL}返回{@code false}其它返回{@code true} * @return true 无此key或值为{@code null}返回{@code false}其它返回{@code true}
*/ */
default boolean isNull(final K key) { default boolean isNull(final K key) {
return JSONUtil.isNull(this.getObj(key)); return ObjUtil.isNull(this.getObj(key));
} }
/** /**
@ -70,7 +71,7 @@ public interface JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K> {
*/ */
default JSONArray getJSONArray(final K key) { default JSONArray getJSONArray(final K key) {
final Object object = this.getObj(key); final Object object = this.getObj(key);
if (JSONUtil.isNull(object)) { if (ObjUtil.isNull(object)) {
return null; return null;
} }
@ -89,7 +90,7 @@ public interface JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K> {
*/ */
default JSONObject getJSONObject(final K key) { default JSONObject getJSONObject(final K key) {
final Object object = this.getObj(key); final Object object = this.getObj(key);
if (JSONUtil.isNull(object)) { if (ObjUtil.isNull(object)) {
return null; return null;
} }
@ -133,7 +134,7 @@ public interface JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K> {
default Date getDate(final K key, final Date defaultValue) { default Date getDate(final K key, final Date defaultValue) {
// 默认转换 // 默认转换
final Object obj = getObj(key); final Object obj = getObj(key);
if (JSONUtil.isNull(obj)) { if (ObjUtil.isNull(obj)) {
return defaultValue; return defaultValue;
} }
if (obj instanceof Date) { if (obj instanceof Date) {
@ -167,7 +168,7 @@ public interface JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K> {
default LocalDateTime getLocalDateTime(final K key, final LocalDateTime defaultValue) { default LocalDateTime getLocalDateTime(final K key, final LocalDateTime defaultValue) {
// 默认转换 // 默认转换
final Object obj = getObj(key); final Object obj = getObj(key);
if (JSONUtil.isNull(obj)) { if (ObjUtil.isNull(obj)) {
return defaultValue; return defaultValue;
} }
if (obj instanceof LocalDateTime) { if (obj instanceof LocalDateTime) {
@ -228,7 +229,7 @@ public interface JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K> {
*/ */
default <T> T get(final K key, final Class<T> type, final boolean ignoreError) throws ConvertException { default <T> T get(final K key, final Class<T> type, final boolean ignoreError) throws ConvertException {
final Object value = this.getObj(key); final Object value = this.getObj(key);
if (JSONUtil.isNull(value)) { if (ObjUtil.isNull(value)) {
return null; return null;
} }
return JSONConverter.jsonConvert(type, value, ignoreError); return JSONConverter.jsonConvert(type, value, ignoreError);

View File

@ -1,46 +0,0 @@
package cn.hutool.json;
import cn.hutool.core.text.StrUtil;
import java.io.Serializable;
/**
* 用于定义{@code null}与Javascript中null相对应<br>
* Java中的{@code null}值在js中表示为undefined
*
* @author Looly
*/
public class JSONNull implements Serializable {
private static final long serialVersionUID = 2633815155870764938L;
/**
* {@code NULL} 对象用于减少歧义来表示Java 中的{@code null} <br>
* {@code NULL.equals(null)} 返回 {@code true}. <br>
* {@code NULL.toString()} 返回 {@code "null"}.
*/
public static final JSONNull NULL = new JSONNull();
/**
* A Null object is equal to the null value and to itself.
* 对象与其本身和{@code null}值相等
*
* @param object An object to test for nullness.
* @return true if the object parameter is the JSONObject.NULL object or null.
*/
@SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
@Override
public boolean equals(final Object object) {
return object == null || (object == this);
}
/**
* Get the "null" string value.
* 获得null字符串
*
* @return The string "null".
*/
@Override
public String toString() {
return StrUtil.NULL;
}
}

View File

@ -1,6 +1,5 @@
package cn.hutool.json; package cn.hutool.json;
import cn.hutool.core.bean.BeanPath;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.func.Filter; import cn.hutool.core.lang.func.Filter;
import cn.hutool.core.lang.mutable.MutableEntry; import cn.hutool.core.lang.mutable.MutableEntry;
@ -182,19 +181,9 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
return this.getOrDefault(key, defaultValue); return this.getOrDefault(key, defaultValue);
} }
@Override
public Object getByPath(final String expression) {
return BeanPath.of(expression).get(this);
}
@Override @Override
public <T> T getByPath(final String expression, final Class<T> resultType) { public <T> T getByPath(final String expression, final Class<T> resultType) {
return JSONConverter.jsonConvert(resultType, getByPath(expression), true); return JSONConverter.jsonConvert(resultType, getByPath(expression), this.config.isIgnoreError());
}
@Override
public void putByPath(final String expression, final Object value) {
BeanPath.of(expression).set(this, value);
} }
/** /**
@ -219,7 +208,23 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
* @throws JSONException 值是无穷数字抛出此异常 * @throws JSONException 值是无穷数字抛出此异常
*/ */
public JSONObject set(final String key, final Object value) throws JSONException { public JSONObject set(final String key, final Object value) throws JSONException {
return set(key, value, null, false); put(key, value, null, false);
return this;
}
/**
* 一次性Put 键值对如果key已经存在抛出异常如果键值中有null值忽略
*
* @param key
* @param value 值对象可以是以下类型: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
* @param filter 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@code null}表示不过滤
* @return this
* @throws JSONException 值是无穷数字键重复抛出异常
* @since 5.8.0
*/
public JSONObject setOnce(final String key, final Object value, final Filter<MutableEntry<String, Object>> filter) throws JSONException {
put(key, value, filter, true);
return this;
} }
/** /**
@ -238,32 +243,6 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
return this; return this;
} }
/**
* 一次性Put 键值对如果key已经存在抛出异常如果键值中有null值忽略
*
* @param key
* @param value 值对象可以是以下类型: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
* @return this.
* @throws JSONException 值是无穷数字键重复抛出异常
*/
public JSONObject putOnce(final String key, final Object value) throws JSONException {
return setOnce(key, value, null);
}
/**
* 一次性Put 键值对如果key已经存在抛出异常如果键值中有null值忽略
*
* @param key
* @param value 值对象可以是以下类型: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
* @param filter 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@code null}表示不过滤
* @return this
* @throws JSONException 值是无穷数字键重复抛出异常
* @since 5.8.0
*/
public JSONObject setOnce(final String key, final Object value, final Filter<MutableEntry<String, Object>> filter) throws JSONException {
return set(key, value, filter, true);
}
/** /**
* 在键和值都为非空的情况下put到JSONObject中 * 在键和值都为非空的情况下put到JSONObject中
* *
@ -272,7 +251,7 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
* @return this. * @return this.
* @throws JSONException 值是无穷数字 * @throws JSONException 值是无穷数字
*/ */
public JSONObject putOpt(final String key, final Object value) throws JSONException { public JSONObject setOpt(final String key, final Object value) throws JSONException {
if (key != null && value != null) { if (key != null && value != null) {
this.set(key, value); this.set(key, value);
} }
@ -287,29 +266,12 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
} }
/** /**
* 积累值类似于set当key对应value已经存在时与value组成新的JSONArray. <br> * 追加值.
* 如果只有一个值此值就是value如果多个值则是添加到新的JSONArray中 * <ul>
* * <li>如果键值对不存在或对应值为{@code null}则value为单独值</li>
* @param key * <li>如果值是一个{@link JSONArray}追加之</li>
* @param value 被积累的值 * <li>如果值是一个其他值则和旧值共同组合为一个{@link JSONArray}</li>
* @return this. * </ul>
* @throws JSONException 如果给定键为{@code null}或者键对应的值存在且为非JSONArray
*/
public JSONObject accumulate(final String key, final Object value) throws JSONException {
InternalJSONUtil.testValidity(value);
final Object object = this.getObj(key);
if (object == null) {
this.set(key, value);
} else if (object instanceof JSONArray) {
((JSONArray) object).set(value);
} else {
this.set(key, JSONUtil.createArray(this.config).set(object).set(value));
}
return this;
}
/**
* 追加值如果key无对应值就添加一个JSONArray其元素只有value如果值已经是一个JSONArray则添加到值JSONArray中
* *
* @param key * @param key
* @param value * @param value
@ -320,11 +282,11 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
InternalJSONUtil.testValidity(value); InternalJSONUtil.testValidity(value);
final Object object = this.getObj(key); final Object object = this.getObj(key);
if (object == null) { if (object == null) {
this.set(key, new JSONArray(this.config).set(value)); this.set(key, value);
} else if (object instanceof JSONArray) { } else if (object instanceof JSONArray) {
this.set(key, ((JSONArray) object).set(value)); ((JSONArray) object).set(value);
} else { } else {
throw new JSONException("JSONObject [" + key + "] is not a JSONArray."); this.set(key, JSONUtil.createArray(this.config).set(object).set(value));
} }
return this; return this;
} }
@ -435,13 +397,13 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
* @param value 值对象. 可以是以下类型: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL. * @param value 值对象. 可以是以下类型: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or the JSONNull.NULL.
* @param filter 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@code null}表示不过滤 * @param filter 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@code null}表示不过滤
* @param checkDuplicate 是否检查重复键如果为{@code true}则出现重复键时抛出{@link JSONException}异常 * @param checkDuplicate 是否检查重复键如果为{@code true}则出现重复键时抛出{@link JSONException}异常
* @return this. * @return 旧值
* @throws JSONException 值是无穷数字抛出此异常 * @throws JSONException 值是无穷数字抛出此异常
* @since 5.8.0 * @since 5.8.0
*/ */
private Object put(String key, Object value, final Filter<MutableEntry<String, Object>> filter, final boolean checkDuplicate) throws JSONException { private Object put(String key, Object value, final Filter<MutableEntry<String, Object>> filter, final boolean checkDuplicate) throws JSONException {
if (null == key) { if (null == key) {
return this; return null;
} }
// 添加前置过滤通过MutablePair实现过滤修改键值对等 // 添加前置过滤通过MutablePair实现过滤修改键值对等
@ -453,12 +415,12 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
value = pair.getValue(); value = pair.getValue();
} else { } else {
// 键值对被过滤 // 键值对被过滤
return this; return null;
} }
} }
final boolean ignoreNullValue = this.config.isIgnoreNullValue(); final boolean ignoreNullValue = this.config.isIgnoreNullValue();
if (ObjUtil.isNull(value) && ignoreNullValue) { if (null == value && ignoreNullValue) {
// 忽略值模式下如果值为空清除key // 忽略值模式下如果值为空清除key
return this.remove(key); return this.remove(key);
} else if (checkDuplicate && containsKey(key)) { } else if (checkDuplicate && containsKey(key)) {

View File

@ -106,7 +106,7 @@ public class JSONParser {
for (; ; ) { for (; ; ) {
if (x.nextClean() == ',') { if (x.nextClean() == ',') {
x.back(); x.back();
jsonArray.addRaw(JSONNull.NULL, filter); jsonArray.addRaw(null, filter);
} else { } else {
x.back(); x.back();
jsonArray.addRaw(x.nextValue(), filter); jsonArray.addRaw(x.nextValue(), filter);

View File

@ -411,7 +411,7 @@ public class JSONTokener {
while (true) { while (true) {
if (this.nextClean() == ',') { if (this.nextClean() == ',') {
this.back(); this.back();
jsonArray.add(JSONNull.NULL); jsonArray.add(null);
} else { } else {
this.back(); this.back();
jsonArray.add(this.nextValue()); jsonArray.add(this.nextValue());

View File

@ -716,7 +716,7 @@ public class JSONUtil {
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
public static Object wrap(final Object object, final JSONConfig jsonConfig) { public static Object wrap(final Object object, final JSONConfig jsonConfig) {
if (object == null) { if (object == null) {
return jsonConfig.isIgnoreNullValue() ? null : JSONNull.NULL; return null;
} }
if (object instanceof JSON // if (object instanceof JSON //
|| ObjUtil.isNull(object) // || ObjUtil.isNull(object) //
@ -836,22 +836,6 @@ public class JSONUtil {
return StrUtil.isWrap(StrUtil.trim(str), '[', ']'); return StrUtil.isWrap(StrUtil.trim(str), '[', ']');
} }
/**
* 是否为null对象null的情况包括
*
* <pre>
* 1. {@code null}
* 2. {@link JSONNull}
* </pre>
*
* @param obj 对象
* @return 是否为null
* @since 4.5.7
*/
public static boolean isNull(final Object obj) {
return null == obj || obj instanceof JSONNull;
}
/** /**
* XML转JSONObject<br> * XML转JSONObject<br>
* 转换过程中一些信息可能会丢失JSON中无法区分节点和属性相同的节点将被处理为JSONArray * 转换过程中一些信息可能会丢失JSON中无法区分节点和属性相同的节点将被处理为JSONArray

View File

@ -14,7 +14,6 @@ import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray; import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONConfig; import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONException; import cn.hutool.json.JSONException;
import cn.hutool.json.JSONNull;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONString; import cn.hutool.json.JSONString;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
@ -96,6 +95,7 @@ public class JSONWriter extends Writer {
* @return this * @return this
*/ */
public JSONWriter beginObj() { public JSONWriter beginObj() {
//noinspection resource
writeRaw(CharUtil.DELIM_START); writeRaw(CharUtil.DELIM_START);
return this; return this;
} }
@ -106,6 +106,7 @@ public class JSONWriter extends Writer {
* @return this * @return this
*/ */
public JSONWriter beginArray() { public JSONWriter beginArray() {
//noinspection resource
writeRaw(CharUtil.BRACKET_START); writeRaw(CharUtil.BRACKET_START);
arrayMode = true; arrayMode = true;
return this; return this;
@ -118,7 +119,9 @@ public class JSONWriter extends Writer {
*/ */
public JSONWriter end() { public JSONWriter end() {
// 换行缩进 // 换行缩进
//noinspection resource
writeLF().writeSpace(indent); writeLF().writeSpace(indent);
//noinspection resource
writeRaw(arrayMode ? CharUtil.BRACKET_END : CharUtil.DELIM_END); writeRaw(arrayMode ? CharUtil.BRACKET_END : CharUtil.DELIM_END);
flush(); flush();
arrayMode = false; arrayMode = false;
@ -135,22 +138,24 @@ public class JSONWriter extends Writer {
*/ */
public JSONWriter writeKey(final String key) { public JSONWriter writeKey(final String key) {
if (needSeparator) { if (needSeparator) {
//noinspection resource
writeRaw(CharUtil.COMMA); writeRaw(CharUtil.COMMA);
} }
// 换行缩进 // 换行缩进
//noinspection resource
writeLF().writeSpace(indentFactor + indent); writeLF().writeSpace(indentFactor + indent);
return writeRaw(JSONUtil.quote(key)); return writeRaw(JSONUtil.quote(key));
} }
/** /**
* 写出值自动处理分隔符和缩进自动判断类型并根据不同类型写出特定格式的值<br> * 写出值自动处理分隔符和缩进自动判断类型并根据不同类型写出特定格式的值<br>
* 如果写出的值为{@code null}或者{@link JSONNull}且配置忽略null则跳过 * 如果写出的值为{@code null}且配置忽略null则跳过
* *
* @param value * @param value
* @return this * @return this
*/ */
public JSONWriter writeValue(final Object value) { public JSONWriter writeValue(final Object value) {
if(JSONUtil.isNull(value) && config.isIgnoreNullValue()){ if (null == value && config.isIgnoreNullValue()) {
return this; return this;
} }
return writeValueDirect(value); return writeValueDirect(value);
@ -159,16 +164,17 @@ public class JSONWriter extends Writer {
/** /**
* 写出字段名及字段值如果字段值是{@code null}且忽略null值则不写出任何内容 * 写出字段名及字段值如果字段值是{@code null}且忽略null值则不写出任何内容
* *
* @param key 字段名 * @param key 字段名
* @param value 字段值 * @param value 字段值
* @return this * @return this
* @since 5.7.6 * @since 5.7.6
*/ */
public JSONWriter writeField(final String key, final Object value){ public JSONWriter writeField(final String key, final Object value) {
if(JSONUtil.isNull(value) && config.isIgnoreNullValue()){ if (null == value && config.isIgnoreNullValue()) {
return this; return this;
} }
//noinspection resource
return writeKey(key).writeValueDirect(value); return writeKey(key).writeValueDirect(value);
} }
@ -192,6 +198,7 @@ public class JSONWriter extends Writer {
} }
// ------------------------------------------------------------------------------ Private methods // ------------------------------------------------------------------------------ Private methods
/** /**
* 写出值自动处理分隔符和缩进自动判断类型并根据不同类型写出特定格式的值 * 写出值自动处理分隔符和缩进自动判断类型并根据不同类型写出特定格式的值
* *
@ -201,11 +208,14 @@ public class JSONWriter extends Writer {
private JSONWriter writeValueDirect(final Object value) { private JSONWriter writeValueDirect(final Object value) {
if (arrayMode) { if (arrayMode) {
if (needSeparator) { if (needSeparator) {
//noinspection resource
writeRaw(CharUtil.COMMA); writeRaw(CharUtil.COMMA);
} }
// 换行缩进 // 换行缩进
//noinspection resource
writeLF().writeSpace(indentFactor + indent); writeLF().writeSpace(indentFactor + indent);
} else { } else {
//noinspection resource
writeRaw(CharUtil.COLON).writeSpace(1); writeRaw(CharUtil.COLON).writeSpace(1);
} }
needSeparator = true; needSeparator = true;
@ -220,24 +230,26 @@ public class JSONWriter extends Writer {
*/ */
private JSONWriter writeObjValue(final Object value) { private JSONWriter writeObjValue(final Object value) {
final int indent = indentFactor + this.indent; final int indent = indentFactor + this.indent;
if (value == null || value instanceof JSONNull) { if (value == null) {
writeRaw(JSONNull.NULL.toString()); //noinspection resource
writeRaw(StrUtil.NULL);
} else if (value instanceof JSON) { } else if (value instanceof JSON) {
((JSON) value).write(writer, indentFactor, indent); ((JSON) value).write(writer, indentFactor, indent);
} else if (value instanceof Map || value instanceof Map.Entry) { } else if (value instanceof Map || value instanceof Map.Entry) {
new JSONObject(value).write(writer, indentFactor, indent); new JSONObject(value).write(writer, indentFactor, indent);
} else if (value instanceof Iterable || value instanceof Iterator || ArrayUtil.isArray(value)) { } else if (value instanceof Iterable || value instanceof Iterator || ArrayUtil.isArray(value)) {
if(value instanceof byte[]){ if (value instanceof byte[]) {
// issue#I59LW4 // issue#I59LW4
// json内容中的bytes默认转为Base64 // json内容中的bytes默认转为Base64
writeStrValue(Base64.encode((byte[]) value)); writeStrValue(Base64.encode((byte[]) value));
}else{ } else {
new JSONArray(value).write(writer, indentFactor, indent); new JSONArray(value).write(writer, indentFactor, indent);
} }
} else if (value instanceof Number) { } else if (value instanceof Number) {
writeNumberValue((Number) value); writeNumberValue((Number) value);
} else if (value instanceof Date || value instanceof Calendar || value instanceof TemporalAccessor) { } else if (value instanceof Date || value instanceof Calendar || value instanceof TemporalAccessor) {
final String format = (null == config) ? null : config.getDateFormat(); final String format = (null == config) ? null : config.getDateFormat();
//noinspection resource
writeRaw(formatDate(value, format)); writeRaw(formatDate(value, format));
} else if (value instanceof Boolean) { } else if (value instanceof Boolean) {
writeBooleanValue((Boolean) value); writeBooleanValue((Boolean) value);
@ -260,6 +272,7 @@ public class JSONWriter extends Writer {
private void writeNumberValue(final Number number) { private void writeNumberValue(final Number number) {
// since 5.6.2可配置是否去除末尾多余0例如如果为true,5.0返回5 // since 5.6.2可配置是否去除末尾多余0例如如果为true,5.0返回5
final boolean isStripTrailingZeros = null == config || config.isStripTrailingZeros(); final boolean isStripTrailingZeros = null == config || config.isStripTrailingZeros();
//noinspection resource
writeRaw(NumberUtil.toStr(number, isStripTrailingZeros)); writeRaw(NumberUtil.toStr(number, isStripTrailingZeros));
} }
@ -269,6 +282,7 @@ public class JSONWriter extends Writer {
* @param value Boolean值 * @param value Boolean值
*/ */
private void writeBooleanValue(final Boolean value) { private void writeBooleanValue(final Boolean value) {
//noinspection resource
writeRaw(value.toString()); writeRaw(value.toString());
} }
@ -287,6 +301,7 @@ public class JSONWriter extends Writer {
throw new JSONException(e); throw new JSONException(e);
} }
if (null != valueStr) { if (null != valueStr) {
//noinspection resource
writeRaw(valueStr); writeRaw(valueStr);
} else { } else {
writeStrValue(jsonString.toString()); writeStrValue(jsonString.toString());
@ -317,6 +332,7 @@ public class JSONWriter extends Writer {
private void writeSpace(final int count) { private void writeSpace(final int count) {
if (indentFactor > 0) { if (indentFactor > 0) {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
//noinspection resource
writeRaw(CharUtil.SPACE); writeRaw(CharUtil.SPACE);
} }
} }
@ -329,6 +345,7 @@ public class JSONWriter extends Writer {
*/ */
private JSONWriter writeLF() { private JSONWriter writeLF() {
if (indentFactor > 0) { if (indentFactor > 0) {
//noinspection resource
writeRaw(CharUtil.LF); writeRaw(CharUtil.LF);
} }
return this; return this;

View File

@ -1,5 +1,6 @@
package cn.hutool.json.xml; package cn.hutool.json.xml;
import cn.hutool.core.text.StrUtil;
import cn.hutool.json.InternalJSONUtil; import cn.hutool.json.InternalJSONUtil;
import cn.hutool.json.JSONException; import cn.hutool.json.JSONException;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
@ -63,7 +64,7 @@ public class JSONXMLParser {
if (x.next() == '[') { if (x.next() == '[') {
string = x.nextCDATA(); string = x.nextCDATA();
if (string.length() > 0) { if (string.length() > 0) {
context.accumulate("content", string); context.append("content", string);
} }
return false; return false;
} }
@ -126,10 +127,10 @@ public class JSONXMLParser {
if (!(token instanceof String)) { if (!(token instanceof String)) {
throw x.syntaxError("Missing value"); throw x.syntaxError("Missing value");
} }
jsonobject.accumulate(string, keepStrings ? token : InternalJSONUtil.stringToValue((String) token)); jsonobject.append(string, keepStrings ? token : InternalJSONUtil.stringToValue((String) token));
token = null; token = null;
} else { } else {
jsonobject.accumulate(string, ""); jsonobject.append(string, "");
} }
} else if (token == XML.SLASH) { } else if (token == XML.SLASH) {
@ -138,9 +139,9 @@ public class JSONXMLParser {
throw x.syntaxError("Misshaped tag"); throw x.syntaxError("Misshaped tag");
} }
if (jsonobject.size() > 0) { if (jsonobject.size() > 0) {
context.accumulate(tagName, jsonobject); context.append(tagName, jsonobject);
} else { } else {
context.accumulate(tagName, ""); context.append(tagName, StrUtil.EMPTY);
} }
return false; return false;
@ -156,18 +157,18 @@ public class JSONXMLParser {
} else if (token instanceof String) { } else if (token instanceof String) {
string = (String) token; string = (String) token;
if (string.length() > 0) { if (string.length() > 0) {
jsonobject.accumulate("content", keepStrings ? token : InternalJSONUtil.stringToValue(string)); jsonobject.append("content", keepStrings ? token : InternalJSONUtil.stringToValue(string));
} }
} else if (token == XML.LT) { } else if (token == XML.LT) {
// Nested element // Nested element
if (parse(x, jsonobject, tagName, keepStrings)) { if (parse(x, jsonobject, tagName, keepStrings)) {
if (jsonobject.size() == 0) { if (jsonobject.size() == 0) {
context.accumulate(tagName, ""); context.append(tagName, "");
} else if (jsonobject.size() == 1 && jsonobject.get("content") != null) { } else if (jsonobject.size() == 1 && jsonobject.get("content") != null) {
context.accumulate(tagName, jsonobject.get("content")); context.append(tagName, jsonobject.get("content"));
} else { } else {
context.accumulate(tagName, jsonobject); context.append(tagName, jsonobject);
} }
return false; return false;
} }

View File

@ -166,7 +166,7 @@ public class JSONArrayTest {
@Test @Test
public void toListWithNullTest() { public void toListWithNullTest() {
final String json = "[null,{'akey':'avalue','bkey':'bvalue'}]"; final String json = "[null,{'akey':'avalue','bkey':'bvalue'}]";
final JSONArray ja = JSONUtil.parseArray(json); final JSONArray ja = JSONUtil.parseArray(json, JSONConfig.of().setIgnoreNullValue(false));
final List<KeyBean> list = ja.toList(KeyBean.class); final List<KeyBean> list = ja.toList(KeyBean.class);
Assert.assertNull(list.get(0)); Assert.assertNull(list.get(0));
@ -218,8 +218,13 @@ public class JSONArrayTest {
@Test @Test
public void putToIndexTest(){ public void putToIndexTest(){
final JSONArray jsonArray = new JSONArray(); JSONArray jsonArray = new JSONArray();
jsonArray.put(3, "test"); jsonArray.set(3, "test");
// 默认忽略null值因此空位无值只有一个值
Assert.assertEquals(1, jsonArray.size());
jsonArray = new JSONArray(JSONConfig.of().setIgnoreNullValue(false));
jsonArray.set(3, "test");
// 第三个位置插入值0~2都是null // 第三个位置插入值0~2都是null
Assert.assertEquals(4, jsonArray.size()); Assert.assertEquals(4, jsonArray.size());
} }

View File

@ -12,9 +12,9 @@ public class JSONNullTest {
" \"device_status_date\": null,\n" + " \"device_status_date\": null,\n" +
" \"imsi\": null,\n" + " \"imsi\": null,\n" +
" \"act_date\": \"2021-07-23T06:23:26.000+00:00\"}"); " \"act_date\": \"2021-07-23T06:23:26.000+00:00\"}");
Assert.assertEquals(JSONNull.class, bodyjson.get("device_model").getClass()); Assert.assertNull(bodyjson.get("device_model"));
Assert.assertEquals(JSONNull.class, bodyjson.get("device_status_date").getClass()); Assert.assertNull(bodyjson.get("device_status_date"));
Assert.assertEquals(JSONNull.class, bodyjson.get("imsi").getClass()); Assert.assertNull(bodyjson.get("imsi"));
bodyjson.getConfig().setIgnoreNullValue(true); bodyjson.getConfig().setIgnoreNullValue(true);
Assert.assertEquals("{\"act_date\":\"2021-07-23T06:23:26.000+00:00\"}", bodyjson.toString()); Assert.assertEquals("{\"act_date\":\"2021-07-23T06:23:26.000+00:00\"}", bodyjson.toString());
@ -31,4 +31,26 @@ public class JSONNullTest {
Assert.assertFalse(bodyjson.containsKey("device_status_date")); Assert.assertFalse(bodyjson.containsKey("device_status_date"));
Assert.assertFalse(bodyjson.containsKey("imsi")); Assert.assertFalse(bodyjson.containsKey("imsi"));
} }
@Test
public void setNullTest(){
// 忽略null
String json1 = JSONUtil.createObj().set("key1", null).toString();
Assert.assertEquals("{}", json1);
// 不忽略null
json1 = JSONUtil.createObj(JSONConfig.of().setIgnoreNullValue(false)).set("key1", null).toString();
Assert.assertEquals("{\"key1\":null}", json1);
}
@Test
public void setNullOfJSONArrayTest(){
// 忽略null
String json1 = JSONUtil.createArray().set(null).toString();
Assert.assertEquals("[]", json1);
// 不忽略null
json1 = JSONUtil.createArray(JSONConfig.of().setIgnoreNullValue(false)).set(null).toString();
Assert.assertEquals("[null]", json1);
}
} }

View File

@ -116,7 +116,7 @@ public class JSONObjectTest {
Assert.assertEquals(jsonObject.get("d"), true); Assert.assertEquals(jsonObject.get("d"), true);
Assert.assertTrue(jsonObject.containsKey("e")); Assert.assertTrue(jsonObject.containsKey("e"));
Assert.assertEquals(jsonObject.get("e"), JSONNull.NULL); Assert.assertNull(jsonObject.get("e"));
} }
@Test @Test
@ -460,7 +460,7 @@ public class JSONObjectTest {
json.append("date", DateUtil.parse("2020-06-05 11:16:11")); json.append("date", DateUtil.parse("2020-06-05 11:16:11"));
json.append("bbb", "222"); json.append("bbb", "222");
json.append("aaa", "123"); json.append("aaa", "123");
Assert.assertEquals("{\"date\":[\"2020-06-05 11:16:11\"],\"bbb\":[\"222\"],\"aaa\":[\"123\"]}", json.toString()); Assert.assertEquals("{\"date\":\"2020-06-05 11:16:11\",\"bbb\":\"222\",\"aaa\":\"123\"}", json.toString());
} }
@Test @Test
@ -612,14 +612,14 @@ public class JSONObjectTest {
} }
@Test @Test
public void accumulateTest() { public void appendTest() {
final JSONObject jsonObject = JSONUtil.createObj().accumulate("key1", "value1"); final JSONObject jsonObject = JSONUtil.createObj().append("key1", "value1");
Assert.assertEquals("{\"key1\":\"value1\"}", jsonObject.toString()); Assert.assertEquals("{\"key1\":\"value1\"}", jsonObject.toString());
jsonObject.accumulate("key1", "value2"); jsonObject.append("key1", "value2");
Assert.assertEquals("{\"key1\":[\"value1\",\"value2\"]}", jsonObject.toString()); Assert.assertEquals("{\"key1\":[\"value1\",\"value2\"]}", jsonObject.toString());
jsonObject.accumulate("key1", "value3"); jsonObject.append("key1", "value3");
Assert.assertEquals("{\"key1\":[\"value1\",\"value2\",\"value3\"]}", jsonObject.toString()); Assert.assertEquals("{\"key1\":[\"value1\",\"value2\",\"value3\"]}", jsonObject.toString());
} }