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.math.NumberUtil;
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.util.ArrayUtil;
import cn.hutool.core.util.CharUtil;
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.writer.GlobalValueWriterMapping;
import cn.hutool.json.writer.JSONValueWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Type;
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;
import java.util.*;
import java.util.function.Predicate;
/**
@ -56,9 +57,11 @@ public final class InternalJSONUtil {
* @return 包装后的值null表示此值需被忽略
*/
static Object wrap(final Object object, final JSONConfig jsonConfig) {
if (object == null) {
return null;
// null和自定义对象原样存储
if (null == object || null != InternalJSONUtil.getValueWriter(object)) {
return object;
}
if (object instanceof JSON //
|| object instanceof JSONString //
|| object instanceof CharSequence //
@ -369,7 +372,44 @@ public final class InternalJSONUtil {
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
/**
* 对所有双引号做转义处理使用双反斜杠做转义<br>
* 为了能在HTML中较好的显示会将&lt;/转义为&lt;\/<br>

View File

@ -1,19 +1,11 @@
package cn.hutool.json;
import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.convert.Convert;
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.serialize.JSONString;
import java.io.Serializable;
import java.time.temporal.TemporalAccessor;
import java.util.Comparator;
import java.util.Date;
/**
* JSON配置项
@ -59,35 +51,7 @@ public class JSONConfig implements Serializable {
/**
* 自定义的类型转换器用于在getXXX操作中自动转换类型
*/
private Converter converter = (type, value)->{
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());
};
private Converter converter = JSONConverter.of(this);
/**
* 创建默认的配置项

View File

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

View File

@ -71,6 +71,7 @@ public class JSONTokener {
*
* @param inputStream InputStream
* @param config JSON配置
* @throws JSONException JSON异常包装IO异常
*/
public JSONTokener(final InputStream inputStream, final JSONConfig config) throws JSONException {
this(IoUtil.getUtf8Reader(inputStream), config);
@ -89,6 +90,8 @@ public class JSONTokener {
/**
* 将标记回退到第一个字符重新开始解析新的JSON
*
* @throws JSONException JSON异常包装IO异常
*/
public void back() throws JSONException {
if (this.usePrevious || this.index <= 0) {
@ -111,6 +114,7 @@ public class JSONTokener {
* 源字符串是否有更多的字符
*
* @return 如果未达到结尾返回true否则false
* @throws JSONException JSON异常包装IO异常
*/
public boolean more() throws JSONException {
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 分隔符
* @return 字符串
* @throws JSONException JSON异常包装IO异常
*/
public String nextTo(final char delimiter) throws JSONException {
final StringBuilder sb = new StringBuilder();
@ -297,6 +301,7 @@ public class JSONTokener {
*
* @param delimiters A set of delimiter characters.
* @return A string, trimmed.
* @throws JSONException JSON异常包装IO异常
*/
public String nextTo(final String delimiters) throws JSONException {
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 语法错误
*/
public Object nextValue() throws JSONException {
@ -360,6 +365,7 @@ public class JSONTokener {
*
* @param to 需要定位的字符
* @return 定位的字符如果字符未找到返回0
* @throws JSONException IO异常
*/
public char skipTo(final char to) throws JSONException {
char c;
@ -378,8 +384,8 @@ public class JSONTokener {
return c;
}
} while (c != to);
} catch (final IOException exception) {
throw new JSONException(exception);
} catch (final IOException e) {
throw new JSONException(e);
}
this.back();
return c;
@ -396,43 +402,6 @@ public class JSONTokener {
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.
*

View File

@ -10,12 +10,11 @@ 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.writer.JSONValueWriter;
import cn.hutool.json.writer.JSONWriter;
import cn.hutool.json.xml.JSONXMLUtil;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.io.*;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.util.List;
@ -296,7 +295,18 @@ public class JSONUtil {
* @return JSON字符串
* @since 5.7.12
*/
@SuppressWarnings({"unchecked", "rawtypes"})
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) {
return null;
}

View File

@ -2,39 +2,33 @@ package cn.hutool.json.convert;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.BeanCopier;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.convert.ConvertException;
import cn.hutool.core.convert.Converter;
import cn.hutool.core.convert.RegisterConverter;
import cn.hutool.core.convert.impl.ArrayConverter;
import cn.hutool.core.convert.impl.CollectionConverter;
import cn.hutool.core.convert.impl.MapConverter;
import cn.hutool.core.convert.impl.*;
import cn.hutool.core.map.MapWrapper;
import cn.hutool.core.reflect.ConstructorUtil;
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.json.InternalJSONUtil;
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.*;
import cn.hutool.json.serialize.JSONDeserializer;
import cn.hutool.json.serialize.JSONString;
import java.lang.reflect.Type;
import java.time.temporal.TemporalAccessor;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
/**
* JSON转换器实现Object对象转换为{@link JSON}支持的对象
* <ul>
* <li>String: 转换为相应的对象</li>
* <li>ArrayIterableIterator转换为JSONArray</li>
* <li>Bean对象转为JSONObject</li>
* <li>任意支持的对象转换为JSON</li>
* <li>JSOn转换为指定对象Bean</li>
* </ul>
*
* @author looly
@ -73,27 +67,40 @@ public class JSONConverter implements Converter {
}
@Override
public Object convert(Type targetType, final Object obj) throws ConvertException {
if (null == obj) {
public Object convert(Type targetType, Object value) throws ConvertException {
if (null == value) {
return null;
}
// 对象转JSON
if (targetType instanceof JSON) {
return toJSON(obj);
if (value instanceof JSONString) {
// 被JSONString包装的对象获取其原始类型
value = ((JSONString) value).getRaw();
}
// JSON转对象
if (obj instanceof JSON) {
if (value instanceof JSON) {
if (targetType instanceof TypeReference) {
// 还原原始类型
targetType = ((TypeReference<?>) targetType).getType();
}
return toBean(targetType, (JSON) obj);
return toBean(targetType, (JSON) value);
}
// 无法转换
throw new JSONException("Can not convert from {}: [{}] to [{}]",
obj.getClass().getName(), obj, targetType.getTypeName());
// 对象转JSON
final Class<?> targetClass = TypeUtil.getClass(targetType);
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;
}
// ----------------------------------------------------------- Private method start
/**
* JSON转Bean
*
* @param <T> 目标类型
* @param targetType 目标类型
* @param json JSON
* @return bean
*/
@SuppressWarnings("unchecked")
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) {
return (T) deserializer.deserialize(json);
}
// 其他转换不支持非Class的泛型类型
final Class<T> rawType = (Class<T>) TypeUtil.getClass(targetType);
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等
final T result = toSpecial(targetType, rawType, json);
@ -164,7 +179,7 @@ public class JSONConverter implements Converter {
}
// 跳过异常时返回null
if(json.getConfig().isIgnoreError()){
if (json.getConfig().isIgnoreError()) {
return null;
}
@ -173,8 +188,6 @@ public class JSONConverter implements Converter {
json.getClass().getName(), json, targetType.getTypeName());
}
// ----------------------------------------------------------- Private method start
/**
* 特殊类型转换<br>
* 包括
@ -220,5 +233,18 @@ public class JSONConverter implements Converter {
// 表示非需要特殊转换的对象
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
}

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;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.reflect.NullType;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSON;
import java.lang.reflect.Type;
@ -59,19 +61,6 @@ public class GlobalSerializeMapping {
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) {
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) {
return null;
}
return serializerMap.get(type);
return serializerMap.get(ObjUtil.defaultIfNull(type, NullType.INSTANCE));
}
/**
@ -108,6 +97,19 @@ public class GlobalSerializeMapping {
if (null == deserializerMap) {
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;
import java.io.IOException;
/**
* JSON的值自定义写出
*
@ -14,6 +16,7 @@ public interface JSONValueWriter<T> {
*
* @param writer {@link JSONWriter}
* @param value 被写出的值
* @throws IOException IO异常
*/
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.text.StrUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.InternalJSONUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONConfig;
@ -76,7 +77,7 @@ public class JSONWriter extends Writer {
this.writer = writer;
this.indentFactor = indentFactor;
this.indent = indent;
this.config = config;
this.config = ObjUtil.defaultIfNull(config, JSONConfig.of());
}
/**
@ -298,12 +299,21 @@ public class JSONWriter extends Writer {
* @param predicate 过滤修改器
* @return this
*/
@SuppressWarnings({"unchecked", "rawtypes"})
private JSONWriter writeObjValue(final Object value, final Predicate<MutableEntry<Object, Object>> predicate) {
final int indent = indentFactor + this.indent;
// 自定义规则
final JSONValueWriter valueWriter = InternalJSONUtil.getValueWriter(value);
if(null != valueWriter){
valueWriter.write(this, value);
return this;
}
if (value == null) {
//noinspection resource
writeRaw(StrUtil.NULL);
} else if (value instanceof JSON) {
}else if (value instanceof JSON) {
((JSON) value).write(writer, indentFactor, indent, predicate);
} else if (value instanceof Number) {
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;
}
}