修复JSON反序列化时,引用字段类型的自定义JsonDeserializer无效

This commit is contained in:
Looly 2022-09-04 23:18:42 +08:00
parent 508c139b22
commit 11724c8761
7 changed files with 116 additions and 6 deletions

View File

@ -38,6 +38,7 @@
* 【json 】 解决JSONObject#write无法递归的bugissue#I5OMSC@Gitee
* 【json 】 修复DayOfWeek转json异常问题issue#2572@Github
* 【extra 】 Ftp方法isDir和exist修复及改进pr#2574@Github
* 【json 】 修复JSON反序列化时引用字段类型的自定义JsonDeserializer无效issue#2555@Github
-------------------------------------------------------------------------------------------------------------

View File

@ -36,6 +36,7 @@ import cn.hutool.core.convert.impl.UUIDConverter;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.ClassLoaderUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
@ -279,7 +280,13 @@ public class ConverterRegistry implements Serializable {
// 尝试转Bean
if (BeanUtil.isBean(rowType)) {
return new BeanConverter<T>(type).convert(value, defaultValue);
try {
// 由于5.x设计缺陷JSON转bean无法实现自定义转换因此此处临时使用反射方式获取自定义的转换器此问题会在6.x中彻底解决
final Class<?> clazz = ClassLoaderUtil.loadClass("cn.hutool.json.BeanConverterForJSON");
return ((Converter<T>)ReflectUtil.newInstance(clazz, type)).convert(value, defaultValue);
}catch (final Throwable ignore){
return new BeanConverter<T>(type).convert(value, defaultValue);
}
}
// 无法转换

View File

@ -31,7 +31,7 @@ public class BeanConverter<T> extends AbstractConverter<T> {
private final Type beanType;
private final Class<T> beanClass;
private final CopyOptions copyOptions;
protected CopyOptions copyOptions;
/**
* 构造默认转换选项注入失败的字段忽略

View File

@ -0,0 +1,43 @@
package cn.hutool.json;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.impl.BeanConverter;
import cn.hutool.json.serialize.GlobalSerializeMapping;
import cn.hutool.json.serialize.JSONDeserializer;
import java.lang.reflect.Type;
/**
* 针对JSON的Bean转换封装<br>
* 此类时针对5.x中设计缺陷设计的类在ConverterRegistry中通过反射调用
*
* @param <T> Bean类型
* @since 5.8.6
*/
public class BeanConverterForJSON<T> extends BeanConverter<T> {
public BeanConverterForJSON(Type beanType) {
super(beanType);
}
@Override
protected T convertInternal(final Object value) {
final Class<T> targetType = getTargetType();
if (value instanceof JSON) {
final JSONDeserializer<?> deserializer = GlobalSerializeMapping.getDeserializer(targetType);
if (null != deserializer) {
//noinspection unchecked
return (T) deserializer.deserialize((JSON) value);
}
// issue#2212@Github
// 在JSONObject转Bean时读取JSONObject本身的配置文件
if (value instanceof JSONGetter && BeanUtil.hasSetter(targetType)) {
final JSONConfig config = ((JSONGetter<?>) value).getConfig();
this.copyOptions.setIgnoreError(config.isIgnoreError());
}
}
return super.convertInternal(value);
}
}

View File

@ -28,7 +28,7 @@ public class JSONConverter implements Converter<JSON> {
static {
// 注册到转换中心
ConverterRegistry registry = ConverterRegistry.getInstance();
final ConverterRegistry registry = ConverterRegistry.getInstance();
registry.putCustom(JSON.class, JSONConverter.class);
registry.putCustom(JSONObject.class, JSONConverter.class);
registry.putCustom(JSONArray.class, JSONConverter.class);

View File

@ -768,11 +768,16 @@ public class JSONUtil {
if (null != serializer) {
final Type jsonType = TypeUtil.getTypeArgument(serializer.getClass());
if (null != jsonType) {
final JSON json;
if (serializer instanceof JSONObjectSerializer) {
serializer.serialize(new JSONObject(jsonConfig), object);
json = new JSONObject(jsonConfig);
} else if (serializer instanceof JSONArraySerializer) {
serializer.serialize(new JSONArray(jsonConfig), object);
json = new JSONArray(jsonConfig);
} else{
throw new JSONException("Unsupported JSONSerializer type: " + serializer.getClass());
}
serializer.serialize(json, object);
return json;
}
}
@ -810,7 +815,7 @@ public class JSONUtil {
// 默认按照JSONObject对待
return new JSONObject(object, jsonConfig);
} catch (Exception exception) {
} catch (final Exception exception) {
return null;
}
}

View File

@ -0,0 +1,54 @@
import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.json.serialize.JSONDeserializer;
import cn.hutool.json.serialize.JSONObjectSerializer;
import lombok.Data;
import org.junit.Assert;
import org.junit.Test;
public class Issue2555Test {
@Test
public void serAndDeserTest(){
JSONUtil.putSerializer(MyType.class, new MySerializer());
JSONUtil.putDeserializer(MyType.class, new MyDeserializer());
final SimpleObj simpleObj = new SimpleObj();
final MyType child = new MyType();
child.setAddress("addrValue1");
simpleObj.setMyType(child);
final String json = JSONUtil.toJsonStr(simpleObj);
Assert.assertEquals("{\"myType\":{\"addr\":\"addrValue1\"}}", json);
//MyDeserializer不会被调用
final SimpleObj simpleObj2 = JSONUtil.toBean(json, SimpleObj.class);
Assert.assertEquals("addrValue1", simpleObj2.getMyType().getAddress());
}
@Data
public static class MyType {
private String address;
}
@Data
public static class SimpleObj {
private MyType myType;
}
public static class MySerializer implements JSONObjectSerializer<MyType> {
@Override
public void serialize(JSONObject json, MyType bean) {
json.set("addr", bean.getAddress());
}
}
public static class MyDeserializer implements JSONDeserializer<MyType>{
@Override
public MyType deserialize(JSON json) {
final MyType myType = new MyType();
myType.setAddress(((JSONObject)json).getStr("addr"));
return myType;
}
}
}