This commit is contained in:
Looly 2022-10-09 01:12:02 +08:00
parent bcdbf5537c
commit 3ece54bf58
14 changed files with 312 additions and 185 deletions

View File

@ -0,0 +1,23 @@
package cn.hutool.core.reflect;
import java.lang.reflect.Type;
/**
* 空类型表示
*
* @author looly
* @since 6.0.0
*/
public class NullType implements Type {
/**
* 单例对象
*/
public static NullType INSTANCE = new NullType();
private NullType(){}
@Override
public String toString() {
return "Type of null";
}
}

View File

@ -9,25 +9,26 @@ import cn.hutool.core.map.CaseInsensitiveLinkedMap;
import cn.hutool.core.map.CaseInsensitiveTreeMap; import cn.hutool.core.map.CaseInsensitiveTreeMap;
import cn.hutool.core.math.NumberUtil; import cn.hutool.core.math.NumberUtil;
import cn.hutool.core.reflect.ClassUtil; import cn.hutool.core.reflect.ClassUtil;
import cn.hutool.core.reflect.ConstructorUtil;
import cn.hutool.core.reflect.TypeUtil;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.serialize.GlobalSerializeMapping;
import cn.hutool.json.serialize.JSONDeserializer;
import cn.hutool.json.serialize.JSONString; import cn.hutool.json.serialize.JSONString;
import cn.hutool.json.writer.GlobalValueWriterMapping;
import cn.hutool.json.writer.JSONValueWriter;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.Writer; import java.io.Writer;
import java.lang.reflect.Type;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.sql.SQLException; import java.sql.SQLException;
import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAccessor;
import java.util.Calendar; import java.util.*;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Predicate; import java.util.function.Predicate;
/** /**
@ -56,9 +57,11 @@ public final class InternalJSONUtil {
* @return 包装后的值null表示此值需被忽略 * @return 包装后的值null表示此值需被忽略
*/ */
static Object wrap(final Object object, final JSONConfig jsonConfig) { static Object wrap(final Object object, final JSONConfig jsonConfig) {
if (object == null) { // null和自定义对象原样存储
return null; if (null == object || null != InternalJSONUtil.getValueWriter(object)) {
return object;
} }
if (object instanceof JSON // if (object instanceof JSON //
|| object instanceof JSONString // || object instanceof JSONString //
|| object instanceof CharSequence // || object instanceof CharSequence //
@ -369,7 +372,44 @@ public final class InternalJSONUtil {
return rawHashMap; return rawHashMap;
} }
/**
* 根据值类型获取{@link JSONValueWriter}首先判断对象是否实现了{@link JSONValueWriter}接口<br>
* 如果未实现从{@link GlobalValueWriterMapping}中查找全局的writer否则返回null
*
* @param value
* @param <T> 值类型
* @return {@link JSONValueWriter}
*/
@SuppressWarnings("unchecked")
public static <T> JSONValueWriter<T> getValueWriter(final T value) {
if (value instanceof JSONValueWriter) {
return (JSONValueWriter<T>) value;
}
// 全局自定义序列化支持null的自定义写出
return (JSONValueWriter<T>) GlobalValueWriterMapping.get(null == value ? null : value.getClass());
}
/**
* 根据目标类型获取对应的{@link JSONDeserializer}首先判断是否实现了{@link JSONDeserializer}接口<br>
* 如果未实现从{@link GlobalSerializeMapping}中查找全局的{@link JSONDeserializer}否则返回null
*
* @param targetType 目标类型
* @param <T> 目标类型
* @return {@link JSONDeserializer}
*/
@SuppressWarnings("unchecked")
public static <T> JSONDeserializer<T> getDeserializer(final Type targetType) {
final Class<T> rawType = (Class<T>) TypeUtil.getClass(targetType);
if (null != rawType && JSONDeserializer.class.isAssignableFrom(rawType)) {
return (JSONDeserializer<T>) ConstructorUtil.newInstanceIfPossible(rawType);
}
// 全局自定义反序列化优先级低于实现JSONDeserializer接口
return (JSONDeserializer<T>) GlobalSerializeMapping.getDeserializer(targetType);
}
// --------------------------------------------------------------------------------------------- Private method start // --------------------------------------------------------------------------------------------- Private method start
/** /**
* 对所有双引号做转义处理使用双反斜杠做转义<br> * 对所有双引号做转义处理使用双反斜杠做转义<br>
* 为了能在HTML中较好的显示会将&lt;/转义为&lt;\/<br> * 为了能在HTML中较好的显示会将&lt;/转义为&lt;\/<br>

View File

@ -1,19 +1,11 @@
package cn.hutool.json; package cn.hutool.json;
import cn.hutool.core.comparator.CompareUtil; import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.convert.Converter; import cn.hutool.core.convert.Converter;
import cn.hutool.core.convert.impl.DateConverter;
import cn.hutool.core.convert.impl.TemporalAccessorConverter;
import cn.hutool.core.reflect.TypeUtil;
import cn.hutool.core.text.StrUtil;
import cn.hutool.json.convert.JSONConverter; import cn.hutool.json.convert.JSONConverter;
import cn.hutool.json.serialize.JSONString;
import java.io.Serializable; import java.io.Serializable;
import java.time.temporal.TemporalAccessor;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date;
/** /**
* JSON配置项 * JSON配置项
@ -59,35 +51,7 @@ public class JSONConfig implements Serializable {
/** /**
* 自定义的类型转换器用于在getXXX操作中自动转换类型 * 自定义的类型转换器用于在getXXX操作中自动转换类型
*/ */
private Converter converter = (type, value)->{ private Converter converter = JSONConverter.of(this);
if(null == value){
return null;
}
if(value instanceof JSONString){
// 被JSONString包装的对象获取其原始类型
value = ((JSONString) value).getRaw();
}
final Class<?> rawType = TypeUtil.getClass(type);
if(null == rawType){
return value;
}
if(JSON.class.isAssignableFrom(rawType)){
return JSONConverter.INSTANCE.toJSON(value);
}
if(Date.class.isAssignableFrom(rawType) || TemporalAccessor.class.isAssignableFrom(rawType)){
// 日期转换支持自定义日期格式
final String format = getDateFormat();
if (StrUtil.isNotBlank(format)) {
if (Date.class.isAssignableFrom(rawType)) {
return new DateConverter(format).convert(type, value);
} else {
return new TemporalAccessorConverter(format).convert(type, value);
}
}
}
return Convert.convertWithCheck(type, value, null, isIgnoreError());
};
/** /**
* 创建默认的配置项 * 创建默认的配置项

View File

@ -2,6 +2,7 @@ package cn.hutool.json;
import cn.hutool.core.lang.mutable.Mutable; import cn.hutool.core.lang.mutable.Mutable;
import cn.hutool.core.lang.mutable.MutableEntry; import cn.hutool.core.lang.mutable.MutableEntry;
import cn.hutool.core.util.CharUtil;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -80,7 +81,7 @@ public class JSONParser {
switch (tokener.nextClean()) { switch (tokener.nextClean()) {
case ';': case ';':
case ',': case CharUtil.COMMA:
if (tokener.nextClean() == '}') { if (tokener.nextClean() == '}') {
// issue#2380 // issue#2380
// 尾后逗号Trailing CommasJSON中虽然不支持但是ECMAScript 2017支持此处做兼容 // 尾后逗号Trailing CommasJSON中虽然不支持但是ECMAScript 2017支持此处做兼容
@ -111,7 +112,7 @@ public class JSONParser {
if (x.nextClean() != ']') { if (x.nextClean() != ']') {
x.back(); x.back();
for (; ; ) { for (; ; ) {
if (x.nextClean() == ',') { if (x.nextClean() == CharUtil.COMMA) {
x.back(); x.back();
jsonArray.addRaw(null, predicate); jsonArray.addRaw(null, predicate);
} else { } else {
@ -119,7 +120,7 @@ public class JSONParser {
jsonArray.addRaw(x.nextValue(), predicate); jsonArray.addRaw(x.nextValue(), predicate);
} }
switch (x.nextClean()) { switch (x.nextClean()) {
case ',': case CharUtil.COMMA:
if (x.nextClean() == ']') { if (x.nextClean() == ']') {
return; return;
} }

View File

@ -71,6 +71,7 @@ public class JSONTokener {
* *
* @param inputStream InputStream * @param inputStream InputStream
* @param config JSON配置 * @param config JSON配置
* @throws JSONException JSON异常包装IO异常
*/ */
public JSONTokener(final InputStream inputStream, final JSONConfig config) throws JSONException { public JSONTokener(final InputStream inputStream, final JSONConfig config) throws JSONException {
this(IoUtil.getUtf8Reader(inputStream), config); this(IoUtil.getUtf8Reader(inputStream), config);
@ -89,6 +90,8 @@ public class JSONTokener {
/** /**
* 将标记回退到第一个字符重新开始解析新的JSON * 将标记回退到第一个字符重新开始解析新的JSON
*
* @throws JSONException JSON异常包装IO异常
*/ */
public void back() throws JSONException { public void back() throws JSONException {
if (this.usePrevious || this.index <= 0) { if (this.usePrevious || this.index <= 0) {
@ -111,6 +114,7 @@ public class JSONTokener {
* 源字符串是否有更多的字符 * 源字符串是否有更多的字符
* *
* @return 如果未达到结尾返回true否则false * @return 如果未达到结尾返回true否则false
* @throws JSONException JSON异常包装IO异常
*/ */
public boolean more() throws JSONException { public boolean more() throws JSONException {
this.next(); this.next();
@ -272,11 +276,11 @@ public class JSONTokener {
} }
/** /**
* Get the text up but not including the specified character or the end of line, whichever comes first. <br>
* 获得从当前位置直到分隔符不包括分隔符或行尾的的所有字符 * 获得从当前位置直到分隔符不包括分隔符或行尾的的所有字符
* *
* @param delimiter 分隔符 * @param delimiter 分隔符
* @return 字符串 * @return 字符串
* @throws JSONException JSON异常包装IO异常
*/ */
public String nextTo(final char delimiter) throws JSONException { public String nextTo(final char delimiter) throws JSONException {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
@ -297,6 +301,7 @@ public class JSONTokener {
* *
* @param delimiters A set of delimiter characters. * @param delimiters A set of delimiter characters.
* @return A string, trimmed. * @return A string, trimmed.
* @throws JSONException JSON异常包装IO异常
*/ */
public String nextTo(final String delimiters) throws JSONException { public String nextTo(final String delimiters) throws JSONException {
char c; char c;
@ -314,9 +319,9 @@ public class JSONTokener {
} }
/** /**
* 获得下一个值值类型可以是Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the JSONObject.NULL * 获得下一个值值类型可以是Boolean, Double, Integer, JSONArray, JSONObject, Long, or String
* *
* @return Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the JSONObject.NULL * @return Boolean, Double, Integer, JSONArray, JSONObject, Long, or String
* @throws JSONException 语法错误 * @throws JSONException 语法错误
*/ */
public Object nextValue() throws JSONException { public Object nextValue() throws JSONException {
@ -360,6 +365,7 @@ public class JSONTokener {
* *
* @param to 需要定位的字符 * @param to 需要定位的字符
* @return 定位的字符如果字符未找到返回0 * @return 定位的字符如果字符未找到返回0
* @throws JSONException IO异常
*/ */
public char skipTo(final char to) throws JSONException { public char skipTo(final char to) throws JSONException {
char c; char c;
@ -378,8 +384,8 @@ public class JSONTokener {
return c; return c;
} }
} while (c != to); } while (c != to);
} catch (final IOException exception) { } catch (final IOException e) {
throw new JSONException(exception); throw new JSONException(e);
} }
this.back(); this.back();
return c; return c;
@ -396,43 +402,6 @@ public class JSONTokener {
return new JSONException(message + this); return new JSONException(message + this);
} }
/**
* 转为 {@link JSONArray}
*
* @return {@link JSONArray}
*/
public JSONArray toJSONArray() {
final JSONArray jsonArray = new JSONArray(this.config);
if (this.nextClean() != '[') {
throw this.syntaxError("A JSONArray text must start with '['");
}
if (this.nextClean() != ']') {
this.back();
while (true) {
if (this.nextClean() == ',') {
this.back();
jsonArray.add(null);
} else {
this.back();
jsonArray.add(this.nextValue());
}
switch (this.nextClean()) {
case ',':
if (this.nextClean() == ']') {
return jsonArray;
}
this.back();
break;
case ']':
return jsonArray;
default:
throw this.syntaxError("Expected a ',' or ']'");
}
}
}
return jsonArray;
}
/** /**
* Make a printable string of this JSONTokener. * Make a printable string of this JSONTokener.
* *

View File

@ -10,12 +10,11 @@ import cn.hutool.json.serialize.GlobalSerializeMapping;
import cn.hutool.json.serialize.JSONArraySerializer; import cn.hutool.json.serialize.JSONArraySerializer;
import cn.hutool.json.serialize.JSONDeserializer; import cn.hutool.json.serialize.JSONDeserializer;
import cn.hutool.json.serialize.JSONObjectSerializer; import cn.hutool.json.serialize.JSONObjectSerializer;
import cn.hutool.json.writer.JSONValueWriter;
import cn.hutool.json.writer.JSONWriter;
import cn.hutool.json.xml.JSONXMLUtil; import cn.hutool.json.xml.JSONXMLUtil;
import java.io.File; import java.io.*;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.List; import java.util.List;
@ -296,7 +295,18 @@ public class JSONUtil {
* @return JSON字符串 * @return JSON字符串
* @since 5.7.12 * @since 5.7.12
*/ */
@SuppressWarnings({"unchecked", "rawtypes"})
public static String toJsonStr(final Object obj, final JSONConfig jsonConfig) { public static String toJsonStr(final Object obj, final JSONConfig jsonConfig) {
// 自定义规则优先级高于全局规则
final JSONValueWriter valueWriter = InternalJSONUtil.getValueWriter(obj);
if(null != valueWriter){
final StringWriter stringWriter = new StringWriter();
final JSONWriter jsonWriter = JSONWriter.of(stringWriter, 0, 0, null);
// 用户对象自定义实现了JSONValueWriter接口理解为需要自定义输出
valueWriter.write(jsonWriter, obj);
return stringWriter.toString();
}
if (null == obj) { if (null == obj) {
return null; return null;
} }

View File

@ -2,39 +2,33 @@ package cn.hutool.json.convert;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.BeanCopier; import cn.hutool.core.bean.copier.BeanCopier;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.convert.ConvertException; import cn.hutool.core.convert.ConvertException;
import cn.hutool.core.convert.Converter; import cn.hutool.core.convert.Converter;
import cn.hutool.core.convert.RegisterConverter; import cn.hutool.core.convert.RegisterConverter;
import cn.hutool.core.convert.impl.ArrayConverter; import cn.hutool.core.convert.impl.*;
import cn.hutool.core.convert.impl.CollectionConverter;
import cn.hutool.core.convert.impl.MapConverter;
import cn.hutool.core.map.MapWrapper; import cn.hutool.core.map.MapWrapper;
import cn.hutool.core.reflect.ConstructorUtil; import cn.hutool.core.reflect.ConstructorUtil;
import cn.hutool.core.reflect.TypeReference; import cn.hutool.core.reflect.TypeReference;
import cn.hutool.core.reflect.TypeUtil; import cn.hutool.core.reflect.TypeUtil;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.InternalJSONUtil; import cn.hutool.json.*;
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.JSONUtil;
import cn.hutool.json.serialize.GlobalSerializeMapping;
import cn.hutool.json.serialize.JSONDeserializer; import cn.hutool.json.serialize.JSONDeserializer;
import cn.hutool.json.serialize.JSONString;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.time.temporal.TemporalAccessor;
import java.util.Collection; import java.util.Collection;
import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
/** /**
* JSON转换器实现Object对象转换为{@link JSON}支持的对象 * JSON转换器实现Object对象转换为{@link JSON}支持的对象
* <ul> * <ul>
* <li>String: 转换为相应的对象</li> * <li>任意支持的对象转换为JSON</li>
* <li>ArrayIterableIterator转换为JSONArray</li> * <li>JSOn转换为指定对象Bean</li>
* <li>Bean对象转为JSONObject</li>
* </ul> * </ul>
* *
* @author looly * @author looly
@ -73,27 +67,40 @@ public class JSONConverter implements Converter {
} }
@Override @Override
public Object convert(Type targetType, final Object obj) throws ConvertException { public Object convert(Type targetType, Object value) throws ConvertException {
if (null == obj) { if (null == value) {
return null; return null;
} }
if (value instanceof JSONString) {
// 对象转JSON // 被JSONString包装的对象获取其原始类型
if (targetType instanceof JSON) { value = ((JSONString) value).getRaw();
return toJSON(obj);
} }
// JSON转对象 // JSON转对象
if (obj instanceof JSON) { if (value instanceof JSON) {
if (targetType instanceof TypeReference) { if (targetType instanceof TypeReference) {
// 还原原始类型
targetType = ((TypeReference<?>) targetType).getType(); targetType = ((TypeReference<?>) targetType).getType();
} }
return toBean(targetType, (JSON) obj); return toBean(targetType, (JSON) value);
} }
// 无法转换 // 对象转JSON
throw new JSONException("Can not convert from {}: [{}] to [{}]", final Class<?> targetClass = TypeUtil.getClass(targetType);
obj.getClass().getName(), obj, targetType.getTypeName()); if(null != targetClass){
if (JSON.class.isAssignableFrom(targetClass)) {
return toJSON(value);
}
// 自定义日期格式
if(Date.class.isAssignableFrom(targetClass) || TemporalAccessor.class.isAssignableFrom(targetClass)){
final Object date = toDateWithFormat(targetClass, value);
if(null != date){
return date;
}
}
}
return Convert.convertWithCheck(targetType, value, null, config.isIgnoreError());
} }
/** /**
@ -127,22 +134,30 @@ public class JSONConverter implements Converter {
return json; return json;
} }
// ----------------------------------------------------------- Private method start
/**
* JSON转Bean
*
* @param <T> 目标类型
* @param targetType 目标类型
* @param json JSON
* @return bean
*/
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private <T> T toBean(final Type targetType, final JSON json) { private <T> T toBean(final Type targetType, final JSON json) {
final Class<T> rawType = (Class<T>) TypeUtil.getClass(targetType);
if(null != rawType && JSONDeserializer.class.isAssignableFrom(rawType)){
return (T) JSONDeserializerConverter.INSTANCE.convert(targetType, json);
}
// 全局自定义反序列化优先级低于实现JSONDeserializer接口 // 自定义对象反序列化
final JSONDeserializer<?> deserializer = GlobalSerializeMapping.getDeserializer(targetType); final JSONDeserializer<Object> deserializer = InternalJSONUtil.getDeserializer(targetType);
if (null != deserializer) { if (null != deserializer) {
return (T) deserializer.deserialize(json); return (T) deserializer.deserialize(json);
} }
// 其他转换不支持非Class的泛型类型 final Class<T> rawType = (Class<T>) TypeUtil.getClass(targetType);
if (null == rawType) { if (null == rawType) {
throw new JSONException("Can not get class from type: {}", targetType); // 当目标类型不确定时返回原JSON
return (T) json;
//throw new JSONException("Can not get class from type: {}", targetType);
} }
// 特殊类型转换包括CollectionMap强转Array等 // 特殊类型转换包括CollectionMap强转Array等
final T result = toSpecial(targetType, rawType, json); final T result = toSpecial(targetType, rawType, json);
@ -164,7 +179,7 @@ public class JSONConverter implements Converter {
} }
// 跳过异常时返回null // 跳过异常时返回null
if(json.getConfig().isIgnoreError()){ if (json.getConfig().isIgnoreError()) {
return null; return null;
} }
@ -173,8 +188,6 @@ public class JSONConverter implements Converter {
json.getClass().getName(), json, targetType.getTypeName()); json.getClass().getName(), json, targetType.getTypeName());
} }
// ----------------------------------------------------------- Private method start
/** /**
* 特殊类型转换<br> * 特殊类型转换<br>
* 包括 * 包括
@ -220,5 +233,18 @@ public class JSONConverter implements Converter {
// 表示非需要特殊转换的对象 // 表示非需要特殊转换的对象
return null; return null;
} }
private Object toDateWithFormat(final Class<?> targetClass, final Object value){
// 日期转换支持自定义日期格式
final String format = config.getDateFormat();
if (StrUtil.isNotBlank(format)) {
if (Date.class.isAssignableFrom(targetClass)) {
return new DateConverter(format).convert(targetClass, value);
} else {
return new TemporalAccessorConverter(format).convert(targetClass, value);
}
}
return null;
}
// ----------------------------------------------------------- Private method end // ----------------------------------------------------------- Private method end
} }

View File

@ -1,36 +0,0 @@
package cn.hutool.json.convert;
import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.convert.ConvertException;
import cn.hutool.core.reflect.ConstructorUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.serialize.JSONDeserializer;
/**
* 实现了{@link JSONDeserializer}接口的Bean对象转换器用于将指定JSON转换为JSONDeserializer子对象
*
* @author looly
* @since 6.0.0
*/
public class JSONDeserializerConverter extends AbstractConverter {
private static final long serialVersionUID = 1L;
/**
* 单例
*/
public static final JSONDeserializerConverter INSTANCE = new JSONDeserializerConverter();
@Override
protected Object convertInternal(final Class<?> targetClass, final Object value) {
// 自定义反序列化
if (value instanceof JSON) {
final JSONDeserializer<?> target = (JSONDeserializer<?>) ConstructorUtil.newInstanceIfPossible(targetClass);
if (null == target) {
throw new ConvertException("Can not instance target: [{}]", targetClass);
}
return target.deserialize((JSON) value);
}
throw new ConvertException("JSONDeserializer bean must be convert from JSON!");
}
}

View File

@ -1,6 +1,8 @@
package cn.hutool.json.serialize; package cn.hutool.json.serialize;
import cn.hutool.core.map.SafeConcurrentHashMap; import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.reflect.NullType;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSON; import cn.hutool.json.JSON;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@ -59,19 +61,6 @@ public class GlobalSerializeMapping {
putInternal(type, serializer); putInternal(type, serializer);
} }
/**
* 加入自定义的序列化器
*
* @param type 对象类型
* @param serializer 序列化器实现
*/
synchronized private static void putInternal(final Type type, final JSONSerializer<? extends JSON, ?> serializer) {
if (null == serializerMap) {
serializerMap = new ConcurrentHashMap<>();
}
serializerMap.put(type, serializer);
}
/** /**
* 加入自定义的反序列化器 * 加入自定义的反序列化器
* *
@ -82,7 +71,7 @@ public class GlobalSerializeMapping {
if (null == deserializerMap) { if (null == deserializerMap) {
deserializerMap = new ConcurrentHashMap<>(); deserializerMap = new ConcurrentHashMap<>();
} }
deserializerMap.put(type, deserializer); deserializerMap.put(ObjUtil.defaultIfNull(type, NullType.INSTANCE), deserializer);
} }
/** /**
@ -95,7 +84,7 @@ public class GlobalSerializeMapping {
if (null == serializerMap) { if (null == serializerMap) {
return null; return null;
} }
return serializerMap.get(type); return serializerMap.get(ObjUtil.defaultIfNull(type, NullType.INSTANCE));
} }
/** /**
@ -108,6 +97,19 @@ public class GlobalSerializeMapping {
if (null == deserializerMap) { if (null == deserializerMap) {
return null; return null;
} }
return deserializerMap.get(type); return deserializerMap.get(ObjUtil.defaultIfNull(type, NullType.INSTANCE));
}
/**
* 加入自定义的序列化器
*
* @param type 对象类型
* @param serializer 序列化器实现
*/
synchronized private static void putInternal(final Type type, final JSONSerializer<? extends JSON, ?> serializer) {
if (null == serializerMap) {
serializerMap = new ConcurrentHashMap<>();
}
serializerMap.put(ObjUtil.defaultIfNull(type, NullType.INSTANCE), serializer);
} }
} }

View File

@ -0,0 +1,4 @@
/**
* JSON序列化和反序列化提供对象和JSON之间的转换
*/
package cn.hutool.json.serialize;

View File

@ -0,0 +1,44 @@
package cn.hutool.json.writer;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.reflect.NullType;
import cn.hutool.core.util.ObjUtil;
import java.lang.reflect.Type;
import java.util.Map;
/**
* 全局自定义对象写出<br>
* 用户通过此全局定义可针对某些特殊对象
*
* @author looly
* @since 6.0.0
*/
public class GlobalValueWriterMapping {
private static final Map<Type, JSONValueWriter<?>> writerMap;
static {
writerMap = new SafeConcurrentHashMap<>();
}
/**
* 加入自定义的对象值写出规则
*
* @param type 对象类型
* @param writer 自定义对象写出实现
*/
public static void put(final Type type, final JSONValueWriter<?> writer) {
writerMap.put(ObjUtil.defaultIfNull(type, NullType.INSTANCE), writer);
}
/**
* 获取自定义对象值写出规则
*
* @param type 对象类型
* @return 自定义的 {@link JSONValueWriter}
*/
public static JSONValueWriter<?> get(final Type type) {
return writerMap.get(ObjUtil.defaultIfNull(type, NullType.INSTANCE));
}
}

View File

@ -1,5 +1,7 @@
package cn.hutool.json.writer; package cn.hutool.json.writer;
import java.io.IOException;
/** /**
* JSON的值自定义写出 * JSON的值自定义写出
* *
@ -14,6 +16,7 @@ public interface JSONValueWriter<T> {
* *
* @param writer {@link JSONWriter} * @param writer {@link JSONWriter}
* @param value 被写出的值 * @param value 被写出的值
* @throws IOException IO异常
*/ */
void write(JSONWriter writer, T value); void write(JSONWriter writer, T value);
} }

View File

@ -4,6 +4,7 @@ import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.lang.mutable.MutableEntry; import cn.hutool.core.lang.mutable.MutableEntry;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.InternalJSONUtil; import cn.hutool.json.InternalJSONUtil;
import cn.hutool.json.JSON; import cn.hutool.json.JSON;
import cn.hutool.json.JSONConfig; import cn.hutool.json.JSONConfig;
@ -76,7 +77,7 @@ public class JSONWriter extends Writer {
this.writer = writer; this.writer = writer;
this.indentFactor = indentFactor; this.indentFactor = indentFactor;
this.indent = indent; this.indent = indent;
this.config = config; this.config = ObjUtil.defaultIfNull(config, JSONConfig.of());
} }
/** /**
@ -298,12 +299,21 @@ public class JSONWriter extends Writer {
* @param predicate 过滤修改器 * @param predicate 过滤修改器
* @return this * @return this
*/ */
@SuppressWarnings({"unchecked", "rawtypes"})
private JSONWriter writeObjValue(final Object value, final Predicate<MutableEntry<Object, Object>> predicate) { private JSONWriter writeObjValue(final Object value, final Predicate<MutableEntry<Object, Object>> predicate) {
final int indent = indentFactor + this.indent; final int indent = indentFactor + this.indent;
// 自定义规则
final JSONValueWriter valueWriter = InternalJSONUtil.getValueWriter(value);
if(null != valueWriter){
valueWriter.write(this, value);
return this;
}
if (value == null) { if (value == null) {
//noinspection resource //noinspection resource
writeRaw(StrUtil.NULL); writeRaw(StrUtil.NULL);
} else if (value instanceof JSON) { }else if (value instanceof JSON) {
((JSON) value).write(writer, indentFactor, indent, predicate); ((JSON) value).write(writer, indentFactor, indent, predicate);
} else if (value instanceof Number) { } else if (value instanceof Number) {
NumberValueWriter.INSTANCE.write(this, (Number) value); NumberValueWriter.INSTANCE.write(this, (Number) value);

View File

@ -0,0 +1,67 @@
package cn.hutool.json.writer;
import cn.hutool.core.convert.Converter;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONUtil;
import lombok.Data;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class GlobalValueWriterMappingTest {
@Before
public void init(){
GlobalValueWriterMapping.put(CustomSubBean.class, (JSONValueWriter<CustomSubBean>) (writer, value) -> {
writer.writeRaw(String.valueOf(value.getId()));
});
}
@Test
public void customWriteTest(){
final CustomSubBean customBean = new CustomSubBean();
customBean.setId(12);
customBean.setName("aaa");
final String s = JSONUtil.toJsonStr(customBean);
Assert.assertEquals("12", s);
}
@Test
public void customWriteSubTest(){
final CustomSubBean customSubBean = new CustomSubBean();
customSubBean.setId(12);
customSubBean.setName("aaa");
final CustomBean customBean = new CustomBean();
customBean.setId(1);
customBean.setSub(customSubBean);
final String s = JSONUtil.toJsonStr(customBean);
Assert.assertEquals("{\"id\":1,\"sub\":12}", s);
// 自定义转换
final JSONConfig jsonConfig = JSONConfig.of();
final Converter converter = jsonConfig.getConverter();
jsonConfig.setConverter((targetType, value) -> {
if(targetType == CustomSubBean.class){
final CustomSubBean subBean = new CustomSubBean();
subBean.setId((Integer) value);
return subBean;
}
return converter.convert(targetType, value);
});
final CustomBean customBean1 = JSONUtil.parseObj(s, jsonConfig).toBean(CustomBean.class);
Assert.assertEquals(12, customBean1.getSub().getId());
}
@Data
static class CustomSubBean {
private int id;
private String name;
}
@Data
static class CustomBean{
private int id;
private CustomSubBean sub;
}
}