mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
fix code
This commit is contained in:
parent
21bfa0ebff
commit
a4f0f46ab1
@ -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())
|
||||
|
@ -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()) {
|
||||
|
@ -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或者普通String、Number等
|
||||
*/
|
||||
void parse(T value);
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
145
hutool-json/src/main/java/cn/hutool/json/mapper/ArrayMapper.java
Normal file
145
hutool-json/src/main/java/cn/hutool/json/mapper/ArrayMapper.java
Normal 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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* JSON和对象之间的映射封装
|
||||
*
|
||||
* @author Looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
package cn.hutool.json.mapper;
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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>
|
||||
*
|
||||
|
@ -1,4 +1,4 @@
|
||||
package cn.hutool.json;
|
||||
package cn.hutool.json.serialize;
|
||||
|
||||
/**
|
||||
* {@code JSONString}接口定义了一个{@code toJSONString()}<br>
|
@ -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) {
|
||||
|
@ -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";
|
||||
|
@ -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 -> {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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的单元测试
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user