This commit is contained in:
Looly 2022-06-22 22:18:24 +08:00
parent 21bfa0ebff
commit a4f0f46ab1
21 changed files with 571 additions and 471 deletions

View File

@ -6,14 +6,20 @@ import cn.hutool.core.lang.mutable.MutableEntry;
import cn.hutool.core.map.CaseInsensitiveLinkedMap;
import cn.hutool.core.map.CaseInsensitiveTreeMap;
import cn.hutool.core.math.NumberUtil;
import cn.hutool.core.reflect.ClassUtil;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.serialize.JSONString;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
@ -30,17 +36,73 @@ public final class InternalJSONUtil {
}
/**
* 如果对象是Number 且是 NaN or infinite将抛出异常
* 在需要的时候包装对象<br>
* 包装包括
* <ul>
* <li>array or collection = JSONArray</li>
* <li>map = JSONObject</li>
* <li>standard property (Double, String, et al) = 原对象</li>
* <li>来自于java包 = 字符串</li>
* <li>其它 = 尝试包装为JSONObject否则返回{@code null}</li>
* </ul>
*
* @param obj 被检查的对象
* @return 检测后的值
* @throws JSONException If o is a non-finite number.
* @param object 被包装的对象
* @param jsonConfig JSON选项
* @return 包装后的值null表示此值需被忽略
*/
static Object testValidity(final Object obj) throws JSONException {
if (false == ObjUtil.isValidIfNumber(obj)) {
throw new JSONException("JSON does not allow non-finite numbers.");
static Object wrap(final Object object, final JSONConfig jsonConfig) {
if (object == null) {
return null;
}
if (object instanceof JSON //
|| object instanceof JSONString //
|| object instanceof CharSequence //
|| object instanceof Number //
|| ObjUtil.isBasicType(object) //
) {
if (false == ObjUtil.isValidIfNumber(object)) {
throw new JSONException("JSON does not allow non-finite numbers.");
}
return object;
}
try {
// fix issue#1399@Github
if (object instanceof SQLException) {
return object.toString();
}
// JSONArray
if (object instanceof Iterable || ArrayUtil.isArray(object)) {
return new JSONArray(object, jsonConfig);
}
// JSONObject
if (object instanceof Map || object instanceof Map.Entry) {
return new JSONObject(object, jsonConfig);
}
// 日期类型做包装以便自定义输出格式
if (object instanceof Date
|| object instanceof Calendar
|| object instanceof TemporalAccessor
) {
return object;
}
// 枚举类保存其字符串形式4.0.2新增
if (object instanceof Enum) {
return object.toString();
}
// Java内部类不做转换
if (ClassUtil.isJdkClass(object.getClass())) {
return object.toString();
}
// 默认按照JSONObject对待
return new JSONObject(object, jsonConfig);
} catch (final Exception exception) {
return null;
}
return obj;
}
/**
@ -132,7 +194,7 @@ public final class InternalJSONUtil {
/**
* 将Property的键转化为JSON形式<br>
* 用于识别类似于com.luxiaolei.package.hutool这类用点隔开的键<br>
* 用于识别类似于cn.hutool.json这类用点隔开的键<br>
* 注意不允许重复键
*
* @param jsonObject JSONObject
@ -141,7 +203,7 @@ public final class InternalJSONUtil {
* @param predicate 属性过滤器{@link Predicate#test(Object)}{@code true}保留
* @return JSONObject
*/
static JSONObject propertyPut(final JSONObject jsonObject, final Object key, final Object value, final Predicate<MutableEntry<String, Object>> predicate) {
public static JSONObject propertyPut(final JSONObject jsonObject, final Object key, final Object value, final Predicate<MutableEntry<String, Object>> predicate) {
final String[] path = StrUtil.splitToArray(Convert.toStr(key), CharUtil.DOT);
final int last = path.length - 1;
JSONObject target = jsonObject;
@ -184,7 +246,7 @@ public final class InternalJSONUtil {
* @return {@link CopyOptions}
* @since 5.8.0
*/
static CopyOptions toCopyOptions(final JSONConfig config) {
public static CopyOptions toCopyOptions(final JSONConfig config) {
return CopyOptions.of()
.setIgnoreCase(config.isIgnoreCase())
.setIgnoreError(config.isIgnoreError())

View File

@ -8,6 +8,7 @@ import cn.hutool.core.lang.mutable.MutableEntry;
import cn.hutool.core.lang.mutable.MutableObj;
import cn.hutool.core.text.StrJoiner;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.mapper.ArrayMapper;
import cn.hutool.json.serialize.JSONWriter;
import java.io.StringWriter;
@ -148,7 +149,7 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
*/
public JSONArray(final Object object, final JSONConfig jsonConfig, final Predicate<Mutable<Object>> predicate) throws JSONException {
this(DEFAULT_CAPACITY, jsonConfig);
ObjectMapper.of(object).map(this, predicate);
ArrayMapper.of(object, predicate).mapTo(this);
}
// endregion
@ -328,7 +329,18 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
@Override
public boolean add(final Object e) {
return addRaw(JSONUtil.wrap(e, this.config), null);
return add(e, null);
}
/**
* 增加元素
*
* @param e 元素对象自动根据对象类型转换为JSON中的对象
* @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对值的过滤和修改操作{@code null}表示不过滤{@link Predicate#test(Object)}{@code true}保留
* @return 是否加入成功
*/
public boolean add(final Object e, final Predicate<Mutable<Object>> predicate) {
return addRaw(InternalJSONUtil.wrap(e, this.config), predicate);
}
@Override
@ -369,7 +381,7 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
continue;
}
this.add(index);
list.add(JSONUtil.wrap(object, this.config));
list.add(InternalJSONUtil.wrap(object, this.config));
}
return rawList.addAll(index, list);
}
@ -429,7 +441,7 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
if (null == element && config.isIgnoreNullValue()) {
return null;
}
return this.rawList.set(index, JSONUtil.wrap(element, this.config));
return this.rawList.set(index, InternalJSONUtil.wrap(element, this.config));
}
@Override
@ -441,8 +453,7 @@ public class JSONArray implements JSON, JSONGetter<Integer>, List<Object>, Rando
if (index < 0) {
index = 0;
}
InternalJSONUtil.testValidity(element);
this.rawList.add(index, JSONUtil.wrap(element, this.config));
this.rawList.add(index, InternalJSONUtil.wrap(element, this.config));
} else {
if (false == config.isIgnoreNullValue()) {
while (index != this.size()) {

View File

@ -1,19 +0,0 @@
package cn.hutool.json;
/**
* 实现此接口的类可以通过实现{@code parse(value)}方法来将JSON中的值解析为此对象的值<br>
* 此接口主要用于可以自定义的Bean对象而无需全局配置转换器
*
* @author Looly
* @since 5.7.8
*/
public interface JSONBeanParser<T> {
/**
* value转Bean<br>
* 通过实现此接口将JSON中的值填充到当前对象的字段值中即对象自行实现JSON反序列化逻辑
*
* @param value 被解析的对象类型可能为JSON或者普通StringNumber等
*/
void parse(T value);
}

View File

@ -5,6 +5,7 @@ import cn.hutool.core.lang.mutable.MutableEntry;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.MapWrapper;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.mapper.ObjectMapper;
import cn.hutool.json.serialize.JSONWriter;
import java.io.StringWriter;
@ -127,7 +128,7 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
*/
public JSONObject(final Object source, final JSONConfig config, final Predicate<MutableEntry<String, Object>> predicate) {
this(DEFAULT_CAPACITY, config);
ObjectMapper.of(source).map(this, predicate);
ObjectMapper.of(source, predicate).mapTo(this);
}
// -------------------------------------------------------------------------------------------------------------------- Constructor end
@ -279,7 +280,6 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
* @throws JSONException 如果给定键为{@code null}或者键对应的值存在且为非JSONArray
*/
public JSONObject append(final String key, final Object value) throws JSONException {
InternalJSONUtil.testValidity(value);
final Object object = this.getObj(key);
if (object == null) {
this.set(key, value);
@ -426,6 +426,6 @@ public class JSONObject extends MapWrapper<String, Object> implements JSON, JSON
} else if (checkDuplicate && containsKey(key)) {
throw new JSONException("Duplicate key \"{}\"", key);
}
return super.put(key, JSONUtil.wrap(InternalJSONUtil.testValidity(value), this.config));
return super.put(key, InternalJSONUtil.wrap(value, this.config));
}
}

View File

@ -2,6 +2,7 @@ package cn.hutool.json;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.serialize.JSONDeserializer;
import cn.hutool.json.serialize.JSONString;
/**
* JSON支持<br>

View File

@ -4,9 +4,7 @@ import cn.hutool.core.codec.HexUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.map.MapWrapper;
import cn.hutool.core.reflect.ClassUtil;
import cn.hutool.core.reflect.TypeReference;
import cn.hutool.core.reflect.TypeUtil;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjUtil;
@ -14,7 +12,6 @@ import cn.hutool.json.serialize.GlobalSerializeMapping;
import cn.hutool.json.serialize.JSONArraySerializer;
import cn.hutool.json.serialize.JSONDeserializer;
import cn.hutool.json.serialize.JSONObjectSerializer;
import cn.hutool.json.serialize.JSONSerializer;
import java.io.File;
import java.io.IOException;
@ -22,13 +19,8 @@ import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.sql.SQLException;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* JSON工具类
@ -334,7 +326,7 @@ public class JSONUtil {
return StrUtil.str((CharSequence) obj);
}
if(obj instanceof Number){
if (obj instanceof Number) {
return obj.toString();
}
return toJsonStr(parse(obj, jsonConfig));
@ -684,87 +676,6 @@ public class JSONUtil {
return builder.toString();
}
/**
* 在需要的时候包装对象<br>
* 包装包括
* <ul>
* <li>array or collection = JSONArray</li>
* <li>map = JSONObject</li>
* <li>standard property (Double, String, et al) = 原对象</li>
* <li>来自于java包 = 字符串</li>
* <li>其它 = 尝试包装为JSONObject否则返回{@code null}</li>
* </ul>
*
* @param object 被包装的对象
* @param jsonConfig JSON选项
* @return 包装后的值null表示此值需被忽略
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public static Object wrap(final Object object, final JSONConfig jsonConfig) {
if (object == null) {
return null;
}
if (object instanceof JSON //
|| object instanceof JSONString //
|| object instanceof CharSequence //
|| object instanceof Number //
|| ObjUtil.isBasicType(object) //
) {
return object;
}
// 自定义序列化
final JSONSerializer serializer = GlobalSerializeMapping.getSerializer(object.getClass());
if (null != serializer) {
final Type jsonType = TypeUtil.getTypeArgument(serializer.getClass());
if (null != jsonType) {
if (serializer instanceof JSONObjectSerializer) {
serializer.serialize(new JSONObject(jsonConfig), object);
} else if (serializer instanceof JSONArraySerializer) {
serializer.serialize(new JSONArray(jsonConfig), object);
}
}
}
try {
// fix issue#1399@Github
if (object instanceof SQLException) {
return object.toString();
}
// JSONArray
if (object instanceof Iterable || ArrayUtil.isArray(object)) {
return new JSONArray(object, jsonConfig);
}
// JSONObject
if (object instanceof Map || object instanceof Map.Entry) {
return new JSONObject(object, jsonConfig);
}
// 日期类型原样保存便于格式化
if (object instanceof Date
|| object instanceof Calendar
|| object instanceof TemporalAccessor
) {
return object;
}
// 枚举类保存其字符串形式4.0.2新增
if (object instanceof Enum) {
return object.toString();
}
// Java内部类不做转换
if (ClassUtil.isJdkClass(object.getClass())) {
return object.toString();
}
// 默认按照JSONObject对待
return new JSONObject(object, jsonConfig);
} catch (final Exception exception) {
return null;
}
}
/**
* 格式化JSON字符串此方法并不严格检查JSON的格式正确与否
*
@ -832,11 +743,11 @@ public class JSONUtil {
*
* @param type 对象类型
* @param serializer 序列化器实现
* @see GlobalSerializeMapping#put(Type, JSONArraySerializer)
* @since 4.6.5
* @see GlobalSerializeMapping#putSerializer(Type, JSONObjectSerializer)
* @since 6.0.0
*/
public static void putSerializer(final Type type, final JSONArraySerializer<?> serializer) {
GlobalSerializeMapping.put(type, serializer);
public static void putSerializer(final Type type, final JSONObjectSerializer<?> serializer) {
GlobalSerializeMapping.putSerializer(type, serializer);
}
/**
@ -844,11 +755,11 @@ public class JSONUtil {
*
* @param type 对象类型
* @param serializer 序列化器实现
* @see GlobalSerializeMapping#put(Type, JSONObjectSerializer)
* @since 4.6.5
* @see GlobalSerializeMapping#putSerializer(Type, JSONArraySerializer)
* @since 6.0.0
*/
public static void putSerializer(final Type type, final JSONObjectSerializer<?> serializer) {
GlobalSerializeMapping.put(type, serializer);
public static void putSerializer(final Type type, final JSONArraySerializer<?> serializer) {
GlobalSerializeMapping.putSerializer(type, serializer);
}
/**
@ -856,11 +767,11 @@ public class JSONUtil {
*
* @param type 对象类型
* @param deserializer 反序列化器实现
* @see GlobalSerializeMapping#put(Type, JSONDeserializer)
* @see GlobalSerializeMapping#putDeserializer(Type, JSONDeserializer)
* @since 4.6.5
*/
public static void putDeserializer(final Type type, final JSONDeserializer<?> deserializer) {
GlobalSerializeMapping.put(type, deserializer);
GlobalSerializeMapping.putDeserializer(type, deserializer);
}
// --------------------------------------------------------------------------------------------- Private method start

View File

@ -1,267 +0,0 @@
package cn.hutool.json;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.iter.ArrayIter;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.mutable.Mutable;
import cn.hutool.core.lang.mutable.MutableEntry;
import cn.hutool.core.reflect.TypeUtil;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.serialize.GlobalSerializeMapping;
import cn.hutool.json.serialize.JSONObjectSerializer;
import cn.hutool.json.serialize.JSONSerializer;
import java.io.InputStream;
import java.io.Reader;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.function.Predicate;
/**
* 对象和JSON映射器用于转换对象为JSON支持
* <ul>
* <li>Map JSONObject将键值对加入JSON对象</li>
* <li>Map.Entry JSONObject</li>
* <li>CharSequence JSONObject使用JSONTokener解析</li>
* <li>{@link Reader} JSONObject使用JSONTokener解析</li>
* <li>{@link InputStream} JSONObject使用JSONTokener解析</li>
* <li>JSONTokener JSONObject直接解析</li>
* <li>ResourceBundle JSONObject</li>
* <li>Bean JSONObject调用其getters方法getXXX或者isXXX获得值加入到JSON对象例如如果JavaBean对象中有个方法getName()值为"张三"获得的键值对为name: "张三"</li>
* </ul>
*
* @author looly
* @since 5.8.0
*/
public class ObjectMapper {
/**
* 创建ObjectMapper
*
* @param source 来源对象
* @return ObjectMapper
*/
public static ObjectMapper of(final Object source) {
return new ObjectMapper(source);
}
private final Object source;
/**
* 构造
*
* @param source 来源对象
*/
public ObjectMapper(final Object source) {
this.source = source;
}
/**
* 将给定对象转换为{@link JSONObject}
*
* @param jsonObject 目标{@link JSONObject}
* @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@link Predicate#test(Object)}{@code true}保留
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public void map(final JSONObject jsonObject, final Predicate<MutableEntry<String, Object>> predicate) {
final Object source = this.source;
if (null == source) {
return;
}
// 自定义序列化
final JSONSerializer serializer = GlobalSerializeMapping.getSerializer(source.getClass());
if (serializer instanceof JSONObjectSerializer) {
serializer.serialize(jsonObject, source);
return;
}
if (source instanceof JSONArray) {
// 不支持集合类型转换为JSONObject
throw new JSONException("Unsupported type [{}] to JSONObject!", source.getClass());
}
if (source instanceof Map) {
// Map
for (final Map.Entry<?, ?> e : ((Map<?, ?>) source).entrySet()) {
jsonObject.set(Convert.toStr(e.getKey()), e.getValue(), predicate, false);
}
} else if (source instanceof Map.Entry) {
final Map.Entry entry = (Map.Entry) source;
jsonObject.set(Convert.toStr(entry.getKey()), entry.getValue(), predicate, false);
} else if (source instanceof CharSequence) {
// 可能为JSON字符串
mapFromStr((CharSequence) source, jsonObject, predicate);
} else if (source instanceof Reader) {
mapFromTokener(new JSONTokener((Reader) source, jsonObject.getConfig()), jsonObject, predicate);
} else if (source instanceof InputStream) {
mapFromTokener(new JSONTokener((InputStream) source, jsonObject.getConfig()), jsonObject, predicate);
} else if (source instanceof byte[]) {
mapFromTokener(new JSONTokener(IoUtil.toStream((byte[]) source), jsonObject.getConfig()), jsonObject, predicate);
} else if (source instanceof JSONTokener) {
// JSONTokener
mapFromTokener((JSONTokener) source, jsonObject, predicate);
} else if (source instanceof ResourceBundle) {
// JSONTokener
mapFromResourceBundle((ResourceBundle) source, jsonObject, predicate);
} else if (BeanUtil.isReadableBean(source.getClass())) {
// 普通Bean
mapFromBean(source, jsonObject, predicate);
} else {
// 不支持对象类型转换为JSONObject
throw new JSONException("Unsupported type [{}] to JSONObject!", source.getClass());
}
}
/**
* 将给定对象转换为{@link JSONArray}
*
* @param jsonArray 目标{@link JSONArray}
* @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对值的过滤和修改操作{@code null}表示不过滤{@link Predicate#test(Object)}{@code true}保留
* @throws JSONException 非数组或集合
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public void map(final JSONArray jsonArray, final Predicate<Mutable<Object>> predicate) throws JSONException {
final Object source = this.source;
if (null == source) {
return;
}
final JSONSerializer serializer = GlobalSerializeMapping.getSerializer(source.getClass());
if (null != serializer && JSONArray.class.equals(TypeUtil.getTypeArgument(serializer.getClass()))) {
// 自定义序列化
serializer.serialize(jsonArray, source);
} else if (source instanceof CharSequence) {
// JSON字符串
mapFromStr((CharSequence) source, jsonArray, predicate);
} else if (source instanceof Reader) {
mapFromTokener(new JSONTokener((Reader) source, jsonArray.getConfig()), jsonArray, predicate);
} else if (source instanceof InputStream) {
mapFromTokener(new JSONTokener((InputStream) source, jsonArray.getConfig()), jsonArray, predicate);
} else if (source instanceof byte[]) {
final byte[] bytesSource = (byte[]) source;
if ('[' == bytesSource[0] && ']' == bytesSource[bytesSource.length - 1]) {
mapFromTokener(new JSONTokener(IoUtil.toStream(bytesSource), jsonArray.getConfig()), jsonArray, predicate);
} else {
// https://github.com/dromara/hutool/issues/2369
// 非标准的二进制流则按照普通数组对待
for (final byte b : bytesSource) {
jsonArray.add(b);
}
}
} else if (source instanceof JSONTokener) {
mapFromTokener((JSONTokener) source, jsonArray, predicate);
} else {
final Iterator<?> iter;
if (ArrayUtil.isArray(source)) {// 数组
iter = new ArrayIter<>(source);
} else if (source instanceof Iterator<?>) {// Iterator
iter = ((Iterator<?>) source);
} else if (source instanceof Iterable<?>) {// Iterable
iter = ((Iterable<?>) source).iterator();
} else {
throw new JSONException("JSONArray initial value should be a string or collection or array.");
}
final JSONConfig config = jsonArray.getConfig();
Object next;
while (iter.hasNext()) {
next = iter.next();
// 检查循环引用
if (next != source) {
jsonArray.addRaw(JSONUtil.wrap(next, config), predicate);
}
}
}
}
/**
* {@link ResourceBundle}转换
*
* @param bundle ResourceBundle
* @param jsonObject {@link JSONObject}
* @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@code null}表示不过滤{@link Predicate#test(Object)}{@code true}保留
* @since 5.3.1
*/
private static void mapFromResourceBundle(final ResourceBundle bundle, final JSONObject jsonObject, final Predicate<MutableEntry<String, Object>> predicate) {
final Enumeration<String> keys = bundle.getKeys();
while (keys.hasMoreElements()) {
final String key = keys.nextElement();
if (key != null) {
InternalJSONUtil.propertyPut(jsonObject, key, bundle.getString(key), predicate);
}
}
}
/**
* 从字符串转换
*
* @param source JSON字符串
* @param jsonObject {@link JSONObject}
* @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@code null}表示不过滤{@link Predicate#test(Object)}{@code true}保留
*/
private static void mapFromStr(final CharSequence source, final JSONObject jsonObject, final Predicate<MutableEntry<String, Object>> predicate) {
final String jsonStr = StrUtil.trim(source);
if (StrUtil.startWith(jsonStr, '<')) {
// 可能为XML
XML.toJSONObject(jsonObject, jsonStr, false);
return;
}
mapFromTokener(new JSONTokener(StrUtil.trim(source), jsonObject.getConfig()), jsonObject, predicate);
}
/**
* 初始化
*
* @param source JSON字符串
* @param jsonArray {@link JSONArray}
* @param predicate 值过滤编辑器可以通过实现此接口完成解析前对值的过滤和修改操作{@code null}表示不过滤{@link Predicate#test(Object)}{@code true}保留
*/
private void mapFromStr(final CharSequence source, final JSONArray jsonArray, final Predicate<Mutable<Object>> predicate) {
if (null != source) {
mapFromTokener(new JSONTokener(StrUtil.trim(source), jsonArray.getConfig()), jsonArray, predicate);
}
}
/**
* {@link JSONTokener}转换
*
* @param x JSONTokener
* @param jsonObject {@link JSONObject}
* @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@link Predicate#test(Object)}{@code true}保留
*/
private static void mapFromTokener(final JSONTokener x, final JSONObject jsonObject, final Predicate<MutableEntry<String, Object>> predicate) {
JSONParser.of(x).parseTo(jsonObject, predicate);
}
/**
* 初始化
*
* @param x {@link JSONTokener}
* @param jsonArray {@link JSONArray}
* @param predicate 值过滤编辑器可以通过实现此接口完成解析前对值的过滤和修改操作{@code null}表示不过滤{@link Predicate#test(Object)}{@code true}保留
*/
private static void mapFromTokener(final JSONTokener x, final JSONArray jsonArray, final Predicate<Mutable<Object>> predicate) {
JSONParser.of(x).parseTo(jsonArray, predicate);
}
/**
* 从Bean转换
*
* @param bean Bean对象
* @param predicate 过滤器{@link Predicate#test(Object)}{@code true}保留null表示保留
* @param jsonObject {@link JSONObject}
*/
private static void mapFromBean(final Object bean, final JSONObject jsonObject, final Predicate<MutableEntry<String, Object>> predicate) {
final CopyOptions copyOptions = InternalJSONUtil.toCopyOptions(jsonObject.getConfig());
if (null != predicate) {
copyOptions.setFieldEditor((entry -> predicate.test(entry) ? entry : null));
}
BeanUtil.beanToMap(bean, jsonObject, copyOptions);
}
}

View File

@ -0,0 +1,145 @@
package cn.hutool.json.mapper;
import cn.hutool.core.collection.iter.ArrayIter;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.mutable.Mutable;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONException;
import cn.hutool.json.JSONParser;
import cn.hutool.json.JSONTokener;
import cn.hutool.json.serialize.GlobalSerializeMapping;
import cn.hutool.json.serialize.JSONSerializer;
import java.io.InputStream;
import java.io.Reader;
import java.util.Iterator;
import java.util.function.Predicate;
/**
* 对象和JSONArray映射器用于转换对象为JSONArray支持
* <ul>
* <li>CharSequence JSONArray使用JSONTokener解析</li>
* <li>{@link Reader} JSONArray使用JSONTokener解析</li>
* <li>{@link InputStream} JSONArray使用JSONTokener解析</li>
* <li>JSONTokener JSONArray直接解析</li>
* <li>Iterable JSONArray</li>
* <li>Iterator JSONArray</li>
* <li>数组 JSONArray</li>
* </ul>
*
* @author looly
* @since 6.0.0
*/
public class ArrayMapper {
/**
* 创建ArrayMapper
*
* @param source 来源对象
* @param predicate 值过滤编辑器可以通过实现此接口完成解析前对值的过滤和修改操作{@code null}表示不过滤{@link Predicate#test(Object)}{@code true}保留
* @return ObjectMapper
*/
public static ArrayMapper of(final Object source, final Predicate<Mutable<Object>> predicate) {
return new ArrayMapper(source, predicate);
}
private final Object source;
private final Predicate<Mutable<Object>> predicate;
/**
* 构造
*
* @param source 来源对象
* @param predicate 值过滤编辑器可以通过实现此接口完成解析前对值的过滤和修改操作{@code null}表示不过滤{@link Predicate#test(Object)}{@code true}保留
*/
public ArrayMapper(final Object source, final Predicate<Mutable<Object>> predicate) {
this.source = source;
this.predicate = predicate;
}
/**
* 将给定对象转换为{@link JSONArray}
*
* @param jsonArray 目标{@link JSONArray}
* @throws JSONException 非数组或集合
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public void mapTo(final JSONArray jsonArray) throws JSONException {
final Object source = this.source;
if (null == source) {
return;
}
// 自定义序列化
final JSONSerializer serializer = GlobalSerializeMapping.getSerializer(source.getClass());
if (null != serializer) {
serializer.serialize(jsonArray, source);
return;
}
if (source instanceof CharSequence) {
// JSON字符串
mapFromStr((CharSequence) source, jsonArray);
} else if (source instanceof Reader) {
mapFromTokener(new JSONTokener((Reader) source, jsonArray.getConfig()), jsonArray);
} else if (source instanceof InputStream) {
mapFromTokener(new JSONTokener((InputStream) source, jsonArray.getConfig()), jsonArray);
} else if (source instanceof byte[]) {
final byte[] bytesSource = (byte[]) source;
if ('[' == bytesSource[0] && ']' == bytesSource[bytesSource.length - 1]) {
mapFromTokener(new JSONTokener(IoUtil.toStream(bytesSource), jsonArray.getConfig()), jsonArray);
} else {
// https://github.com/dromara/hutool/issues/2369
// 非标准的二进制流则按照普通数组对待
for (final byte b : bytesSource) {
jsonArray.add(b);
}
}
} else if (source instanceof JSONTokener) {
mapFromTokener((JSONTokener) source, jsonArray);
} else {
final Iterator<?> iter;
if (ArrayUtil.isArray(source)) {// 数组
iter = new ArrayIter<>(source);
} else if (source instanceof Iterator<?>) {// Iterator
iter = ((Iterator<?>) source);
} else if (source instanceof Iterable<?>) {// Iterable
iter = ((Iterable<?>) source).iterator();
} else {
throw new JSONException("JSONArray initial value should be a string or collection or array.");
}
Object next;
while (iter.hasNext()) {
next = iter.next();
// 检查循环引用
if (next != source) {
jsonArray.add(next, predicate);
}
}
}
}
/**
* 初始化
*
* @param source JSON字符串
* @param jsonArray {@link JSONArray}
*/
private void mapFromStr(final CharSequence source, final JSONArray jsonArray) {
if (null != source) {
mapFromTokener(new JSONTokener(StrUtil.trim(source), jsonArray.getConfig()), jsonArray);
}
}
/**
* 初始化
*
* @param x {@link JSONTokener}
* @param jsonArray {@link JSONArray}
*/
private void mapFromTokener(final JSONTokener x, final JSONArray jsonArray) {
JSONParser.of(x).parseTo(jsonArray, this.predicate);
}
}

View File

@ -0,0 +1,181 @@
package cn.hutool.json.mapper;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.mutable.MutableEntry;
import cn.hutool.core.text.StrUtil;
import cn.hutool.json.InternalJSONUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONException;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONParser;
import cn.hutool.json.JSONTokener;
import cn.hutool.json.XML;
import cn.hutool.json.serialize.GlobalSerializeMapping;
import cn.hutool.json.serialize.JSONSerializer;
import java.io.InputStream;
import java.io.Reader;
import java.util.Enumeration;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.function.Predicate;
/**
* 对象和JSONObject映射器用于转换对象为JSONObject支持
* <ul>
* <li>Map JSONObject将键值对加入JSON对象</li>
* <li>Map.Entry JSONObject</li>
* <li>CharSequence JSONObject使用JSONTokener解析</li>
* <li>{@link Reader} JSONObject使用JSONTokener解析</li>
* <li>{@link InputStream} JSONObject使用JSONTokener解析</li>
* <li>JSONTokener JSONObject直接解析</li>
* <li>ResourceBundle JSONObject</li>
* <li>Bean JSONObject调用其getters方法getXXX或者isXXX获得值加入到JSON对象例如如果JavaBean对象中有个方法getName()值为"张三"获得的键值对为name: "张三"</li>
* </ul>
*
* @author looly
* @since 5.8.0
*/
public class ObjectMapper {
/**
* 创建ObjectMapper
*
* @param source 来源对象
* @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@link Predicate#test(Object)}{@code true}保留
* @return ObjectMapper
*/
public static ObjectMapper of(final Object source, final Predicate<MutableEntry<String, Object>> predicate) {
return new ObjectMapper(source, predicate);
}
private final Object source;
private final Predicate<MutableEntry<String, Object>> predicate;
/**
* 构造
*
* @param source 来源对象
* @param predicate 键值对过滤编辑器可以通过实现此接口完成解析前对键值对的过滤和修改操作{@link Predicate#test(Object)}{@code true}保留
*/
public ObjectMapper(final Object source, final Predicate<MutableEntry<String, Object>> predicate) {
this.source = source;
this.predicate = predicate;
}
/**
* 将给定对象转换为{@link JSONObject}
*
* @param jsonObject 目标{@link JSONObject}
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public void mapTo(final JSONObject jsonObject) {
final Object source = this.source;
if (null == source) {
return;
}
// 自定义序列化
final JSONSerializer serializer = GlobalSerializeMapping.getSerializer(source.getClass());
if (null != serializer) {
serializer.serialize(jsonObject, source);
return;
}
if (source instanceof JSONArray) {
// 不支持集合类型转换为JSONObject
throw new JSONException("Unsupported type [{}] to JSONObject!", source.getClass());
}
if (source instanceof Map) {
// Map
for (final Map.Entry<?, ?> e : ((Map<?, ?>) source).entrySet()) {
jsonObject.set(Convert.toStr(e.getKey()), e.getValue(), predicate, false);
}
} else if (source instanceof Map.Entry) {
final Map.Entry entry = (Map.Entry) source;
jsonObject.set(Convert.toStr(entry.getKey()), entry.getValue(), predicate, false);
} else if (source instanceof CharSequence) {
// 可能为JSON字符串
mapFromStr((CharSequence) source, jsonObject);
} else if (source instanceof Reader) {
mapFromTokener(new JSONTokener((Reader) source, jsonObject.getConfig()), jsonObject);
} else if (source instanceof InputStream) {
mapFromTokener(new JSONTokener((InputStream) source, jsonObject.getConfig()), jsonObject);
} else if (source instanceof byte[]) {
mapFromTokener(new JSONTokener(IoUtil.toStream((byte[]) source), jsonObject.getConfig()), jsonObject);
} else if (source instanceof JSONTokener) {
// JSONTokener
mapFromTokener((JSONTokener) source, jsonObject);
} else if (source instanceof ResourceBundle) {
// JSONTokener
mapFromResourceBundle((ResourceBundle) source, jsonObject);
} else if (BeanUtil.isReadableBean(source.getClass())) {
// 普通Bean
mapFromBean(source, jsonObject);
} else {
// 不支持对象类型转换为JSONObject
throw new JSONException("Unsupported type [{}] to JSONObject!", source.getClass());
}
}
/**
* {@link ResourceBundle}转换
*
* @param bundle ResourceBundle
* @param jsonObject {@link JSONObject}
* @since 5.3.1
*/
private void mapFromResourceBundle(final ResourceBundle bundle, final JSONObject jsonObject) {
final Enumeration<String> keys = bundle.getKeys();
while (keys.hasMoreElements()) {
final String key = keys.nextElement();
if (key != null) {
InternalJSONUtil.propertyPut(jsonObject, key, bundle.getString(key), this.predicate);
}
}
}
/**
* 从字符串转换
*
* @param source JSON字符串
* @param jsonObject {@link JSONObject}
*/
private void mapFromStr(final CharSequence source, final JSONObject jsonObject) {
final String jsonStr = StrUtil.trim(source);
if (StrUtil.startWith(jsonStr, '<')) {
// 可能为XML
XML.toJSONObject(jsonObject, jsonStr, false);
return;
}
mapFromTokener(new JSONTokener(StrUtil.trim(source), jsonObject.getConfig()), jsonObject);
}
/**
* {@link JSONTokener}转换
*
* @param x JSONTokener
* @param jsonObject {@link JSONObject}
*/
private void mapFromTokener(final JSONTokener x, final JSONObject jsonObject) {
JSONParser.of(x).parseTo(jsonObject, this.predicate);
}
/**
* 从Bean转换
*
* @param bean Bean对象
* @param jsonObject {@link JSONObject}
*/
private void mapFromBean(final Object bean, final JSONObject jsonObject) {
final CopyOptions copyOptions = InternalJSONUtil.toCopyOptions(jsonObject.getConfig());
if (null != this.predicate) {
copyOptions.setFieldEditor((entry -> this.predicate.test(entry) ? entry : null));
}
BeanUtil.beanToMap(bean, jsonObject, copyOptions);
}
}

View File

@ -0,0 +1,7 @@
/**
* JSON和对象之间的映射封装
*
* @author Looly
* @since 6.0.0
*/
package cn.hutool.json.mapper;

View File

@ -0,0 +1,74 @@
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.text.StrUtil;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONUtil;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Date;
/**
* 自定义的日期表示形式<br>
* 支持包括{@link Date}{@link Calendar}{@link TemporalAccessor}
*
* @author looly
* @since 6.0.0
*/
public class DateJSONString implements JSONString {
final Object dateObj;
final JSONConfig jsonConfig;
public DateJSONString(final Object dateObj, final JSONConfig jsonConfig) {
this.dateObj = dateObj;
this.jsonConfig = jsonConfig;
}
@Override
public String toJSONString() {
return formatDate(this.jsonConfig.getDateFormat());
}
/**
* 按照给定格式格式化日期格式为空时返回时间戳字符串
*
* @param format 格式
* @return 日期字符串
*/
private String formatDate(final 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);
}
//默认使用时间戳
final 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);
}
}

View File

@ -11,10 +11,10 @@ import java.util.concurrent.ConcurrentHashMap;
/**
* 全局的序列化和反序列化器映射<br>
* 在JSON和Java对象转换过程中优先使用注册于此处的自定义转换
* 在JSON和Java对象转换过程中优先使用注册于此处的自定义转换<br>
* 分别定义{@link JSONObjectSerializer}{@link JSONArraySerializer}的原因是实际加入对象到JSON中时无法区分是JSONObject还是JSONArray
*
* @author Looly
*
*/
public class GlobalSerializeMapping {
@ -39,33 +39,33 @@ public class GlobalSerializeMapping {
}
/**
* 加入自定义的序列化器
* 加入自定义的JSONArray序列化器
*
* @param type 对象类型
* @param type 对象类型
* @param serializer 序列化器实现
*/
public static void put(final Type type, final JSONArraySerializer<?> serializer) {
public static void putSerializer(final Type type, final JSONArraySerializer<?> serializer) {
putInternal(type, serializer);
}
/**
* 加入自定义的JSONObject序列化器
*
* @param type 对象类型
* @param serializer 序列化器实现
*/
public static void putSerializer(final Type type, final JSONObjectSerializer<?> serializer) {
putInternal(type, serializer);
}
/**
* 加入自定义的序列化器
*
* @param type 对象类型
* @param serializer 序列化器实现
*/
public static void put(final Type type, final JSONObjectSerializer<?> serializer) {
putInternal(type, serializer);
}
/**
* 加入自定义的序列化器
*
* @param type 对象类型
* @param type 对象类型
* @param serializer 序列化器实现
*/
synchronized private static void putInternal(final Type type, final JSONSerializer<? extends JSON, ?> serializer) {
if(null == serializerMap) {
if (null == serializerMap) {
serializerMap = new ConcurrentHashMap<>();
}
serializerMap.put(type, serializer);
@ -74,11 +74,11 @@ public class GlobalSerializeMapping {
/**
* 加入自定义的反序列化器
*
* @param type 对象类型
* @param type 对象类型
* @param deserializer 反序列化器实现
*/
synchronized public static void put(final Type type, final JSONDeserializer<?> deserializer) {
if(null == deserializerMap) {
synchronized public static void putDeserializer(final Type type, final JSONDeserializer<?> deserializer) {
if (null == deserializerMap) {
deserializerMap = new ConcurrentHashMap<>();
}
deserializerMap.put(type, deserializer);
@ -86,11 +86,12 @@ public class GlobalSerializeMapping {
/**
* 获取自定义的序列化器如果未定义返回{@code null}
*
* @param type 类型
* @return 自定义的序列化器或者{@code null}
*/
public static JSONSerializer<? extends JSON, ?> getSerializer(final Type type){
if(null == serializerMap) {
public static JSONSerializer<? extends JSON, ?> getSerializer(final Type type) {
if (null == serializerMap) {
return null;
}
return serializerMap.get(type);
@ -98,11 +99,12 @@ public class GlobalSerializeMapping {
/**
* 获取自定义的反序列化器如果未定义返回{@code null}
*
* @param type 类型
* @return 自定义的反序列化器或者{@code null}
*/
public static JSONDeserializer<?> getDeserializer(final Type type){
if(null == deserializerMap) {
public static JSONDeserializer<?> getDeserializer(final Type type) {
if (null == deserializerMap) {
return null;
}
return deserializerMap.get(type);

View File

@ -7,7 +7,7 @@ import java.lang.reflect.Type;
/**
* JSON自定义反序列化接口实现JSON to Bean使用方式为
* <ul>
* <li>定义好反序列化规则使用{@link GlobalSerializeMapping#put(Type, JSONDeserializer)}关联指定类型与转换器实现反序列化</li>
* <li>定义好反序列化规则使用{@link GlobalSerializeMapping#putDeserializer(Type, JSONDeserializer)}关联指定类型与转换器实现反序列化</li>
* <li>使Bean实现此接口调用{@link #deserialize(JSON)}解析字段返回this即可</li>
* </ul>
*

View File

@ -1,4 +1,4 @@
package cn.hutool.json;
package cn.hutool.json.serialize;
/**
* {@code JSONString}接口定义了一个{@code toJSONString()}<br>

View File

@ -7,14 +7,10 @@ import cn.hutool.core.date.format.GlobalCustomFormat;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.math.NumberUtil;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONException;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONString;
import cn.hutool.json.JSONUtil;
import java.io.IOException;
@ -22,8 +18,6 @@ import java.io.Writer;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
/**
* JSON数据写出器<br>
@ -234,10 +228,6 @@ public class JSONWriter extends Writer {
writeRaw(StrUtil.NULL);
} else if (value instanceof JSON) {
((JSON) value).write(writer, indentFactor, indent);
} 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) {
writeNumberValue((Number) value);
} else if (value instanceof Date || value instanceof Calendar || value instanceof TemporalAccessor) {
@ -249,7 +239,7 @@ public class JSONWriter extends Writer {
} else if (value instanceof JSONString) {
writeJSONStringValue((JSONString) value);
} else {
writeStrValue(value.toString());
writeQuoteStrValue(value.toString());
}
return this;
@ -297,7 +287,7 @@ public class JSONWriter extends Writer {
//noinspection resource
writeRaw(valueStr);
} else {
writeStrValue(jsonString.toString());
writeQuoteStrValue(jsonString.toString());
}
}
@ -309,7 +299,7 @@ public class JSONWriter extends Writer {
*
* @param csq 字符串
*/
private void writeStrValue(final String csq) {
private void writeQuoteStrValue(final String csq) {
try {
JSONUtil.quote(csq, writer);
} catch (final IOException e) {

View File

@ -15,7 +15,7 @@ import java.time.temporal.TemporalAccessor;
* @author looly
* @since 5.7.22
*/
public class TemporalAccessorSerializer implements JSONObjectSerializer<TemporalAccessor>, JSONDeserializer<TemporalAccessor> {
public class TemporalAccessorSerializer implements JSONSerializer<JSONObject, TemporalAccessor>, JSONDeserializer<TemporalAccessor> {
private static final String YEAR_KEY = "year";
private static final String MONTH_KEY = "month";

View File

@ -3,16 +3,20 @@ package cn.hutool.json;
import cn.hutool.json.serialize.JSONObjectSerializer;
import lombok.ToString;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.Date;
public class CustomSerializeTest {
@Before
public void init(){
JSONUtil.putSerializer(CustomBean.class, (JSONObjectSerializer<CustomBean>) (json, bean) -> json.set("customName", bean.name));
}
@Test
public void serializeTest() {
JSONUtil.putSerializer(CustomBean.class, (JSONObjectSerializer<CustomBean>) (json, bean) -> json.set("customName", bean.name));
final CustomBean customBean = new CustomBean();
customBean.name = "testName";
@ -20,6 +24,15 @@ public class CustomSerializeTest {
Assert.assertEquals("testName", obj.getStr("customName"));
}
@Test
public void putTest() {
final CustomBean customBean = new CustomBean();
customBean.name = "testName";
final JSONObject obj = JSONUtil.createObj().set("customBean", customBean);
Assert.assertEquals("testName", obj.getJSONObject("customBean").getStr("customName"));
}
@Test
public void deserializeTest() {
JSONUtil.putDeserializer(CustomBean.class, json -> {

View File

@ -1,5 +1,6 @@
package cn.hutool.json;
import cn.hutool.core.lang.Console;
import lombok.Data;
import org.junit.Assert;
import org.junit.Test;
@ -10,7 +11,7 @@ import java.time.LocalTime;
import java.time.Month;
/**
* https://github.com/dromara/hutool/issues/2090
* <a href="https://github.com/dromara/hutool/issues/2090">https://github.com/dromara/hutool/issues/2090</a>
*/
public class Issue2090Test {
@ -20,6 +21,7 @@ public class Issue2090Test {
test.setLocalDate(LocalDate.now());
final JSONObject json = JSONUtil.parseObj(test);
Console.log(json);
final TestBean test1 = json.toBean(TestBean.class);
Assert.assertEquals(test, test1);
}

View File

@ -15,7 +15,7 @@ public class IssuesI44E4HTest {
@Test
public void deserializerTest(){
GlobalSerializeMapping.put(TestDto.class, (JSONDeserializer<TestDto>) json -> {
GlobalSerializeMapping.putDeserializer(TestDto.class, (JSONDeserializer<TestDto>) json -> {
final TestDto testDto = new TestDto();
testDto.setMd(new AcBizModuleMd("name1", ((JSONObject)json).getStr("md")));
return testDto;

View File

@ -5,9 +5,7 @@ import cn.hutool.core.annotation.PropIgnore;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ObjUtil;
@ -24,7 +22,6 @@ import cn.hutool.json.test.bean.report.StepReport;
import cn.hutool.json.test.bean.report.SuiteReport;
import lombok.Data;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import java.io.ByteArrayInputStream;
@ -47,13 +44,13 @@ import java.util.Set;
public class JSONObjectTest {
@Test
@Ignore
public void toStringTest() {
final String str = "{\"code\": 500, \"data\":null}";
//noinspection MismatchedQueryAndUpdateOfCollection
final JSONObject jsonObject = new JSONObject(str);
Console.log(jsonObject);
Assert.assertEquals("{\"code\":500,\"data\":null}", jsonObject.toString());
jsonObject.getConfig().setIgnoreNullValue(true);
Console.log(jsonObject.toStringPretty());
Assert.assertEquals("{\"code\":500}", jsonObject.toString());
}
@Test
@ -176,16 +173,6 @@ public class JSONObjectTest {
Assert.assertEquals(new JSONArray(), json.getJSONObject("data").getJSONArray("cards"));
}
@Test
@Ignore
public void parseStringWithBomTest() {
final String jsonStr = FileUtil.readUtf8String("f:/test/jsontest.txt");
final JSONObject json = new JSONObject(jsonStr);
final JSONObject json2 = JSONUtil.parseObj(json);
Console.log(json);
Console.log(json2);
}
@Test
public void parseStringWithSlashTest() {
//在5.3.2之前</div>中的/会被转义修复此bug的单元测试

View File

@ -2,9 +2,9 @@ package cn.hutool.json;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.math.NumberUtil;
import cn.hutool.json.serialize.JSONString;
import cn.hutool.json.test.bean.Price;
import cn.hutool.json.test.bean.UserA;
import cn.hutool.json.test.bean.UserC;
@ -25,8 +25,7 @@ public class JSONUtilTest {
*/
@Test(expected = JSONException.class)
public void parseTest() {
final JSONArray jsonArray = JSONUtil.parseArray("[{\"a\":\"a\\x]");
Console.log(jsonArray);
JSONUtil.parseArray("[{\"a\":\"a\\x]");
}
/**
@ -107,6 +106,7 @@ public class JSONUtilTest {
@Test
public void toJsonStrFromSortedTest() {
//noinspection SerializableInnerClassWithNonSerializableOuterClass
final SortedMap<Object, Object> sortedMap = new TreeMap<Object, Object>() {
private static final long serialVersionUID = 1L;
@ -236,14 +236,14 @@ public class JSONUtilTest {
@Test
public void toJsonStrOfStringTest(){
String a = "a";
final String a = "a";
final String s = JSONUtil.toJsonStr(a);
Assert.assertEquals(a, s);
}
@Test
public void toJsonStrOfNumberTest(){
int a = 1;
final int a = 1;
final String s = JSONUtil.toJsonStr(a);
Assert.assertEquals("1", s);
}