mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
fix code
This commit is contained in:
parent
bcdbf5537c
commit
3ece54bf58
@ -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";
|
||||||
|
}
|
||||||
|
}
|
@ -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中较好的显示,会将</转义为<\/<br>
|
* 为了能在HTML中较好的显示,会将</转义为<\/<br>
|
||||||
|
@ -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());
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建默认的配置项
|
* 创建默认的配置项
|
||||||
|
@ -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 Commas),JSON中虽然不支持,但是ECMAScript 2017支持,此处做兼容。
|
// 尾后逗号(Trailing Commas),JSON中虽然不支持,但是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;
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
*
|
*
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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>Array、Iterable、Iterator:转换为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);
|
||||||
}
|
}
|
||||||
// 特殊类型转换,包括Collection、Map、强转、Array等
|
// 特殊类型转换,包括Collection、Map、强转、Array等
|
||||||
final T result = toSpecial(targetType, rawType, json);
|
final T result = toSpecial(targetType, rawType, json);
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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!");
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
* JSON序列化和反序列化,提供对象和JSON之间的转换
|
||||||
|
*/
|
||||||
|
package cn.hutool.json.serialize;
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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,8 +299,17 @@ 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);
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user