diff --git a/CHANGELOG.md b/CHANGELOG.md index a62bff564..976acb351 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ * 【json 】 解决JSONObject#write无法递归的bug(issue#I5OMSC@Gitee) * 【json 】 修复DayOfWeek转json异常问题(issue#2572@Github) * 【extra 】 Ftp方法isDir和exist修复及改进(pr#2574@Github) +* 【json 】 修复JSON反序列化时,引用字段类型的自定义JsonDeserializer无效(issue#2555@Github) ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java b/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java index 40f62a131..a6903dc92 100755 --- a/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java @@ -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(type).convert(value, defaultValue); + try { + // 由于5.x设计缺陷,JSON转bean无法实现自定义转换,因此此处临时使用反射方式获取自定义的转换器,此问题会在6.x中彻底解决。 + final Class clazz = ClassLoaderUtil.loadClass("cn.hutool.json.BeanConverterForJSON"); + return ((Converter)ReflectUtil.newInstance(clazz, type)).convert(value, defaultValue); + }catch (final Throwable ignore){ + return new BeanConverter(type).convert(value, defaultValue); + } } // 无法转换 diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java index 9a7c23848..5783b561c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/BeanConverter.java @@ -31,7 +31,7 @@ public class BeanConverter extends AbstractConverter { private final Type beanType; private final Class beanClass; - private final CopyOptions copyOptions; + protected CopyOptions copyOptions; /** * 构造,默认转换选项,注入失败的字段忽略 diff --git a/hutool-json/src/main/java/cn/hutool/json/BeanConverterForJSON.java b/hutool-json/src/main/java/cn/hutool/json/BeanConverterForJSON.java new file mode 100755 index 000000000..969a99976 --- /dev/null +++ b/hutool-json/src/main/java/cn/hutool/json/BeanConverterForJSON.java @@ -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转换封装。
+ * 此类时针对5.x中设计缺陷设计的类,在ConverterRegistry中通过反射调用 + * + * @param Bean类型 + * @since 5.8.6 + */ +public class BeanConverterForJSON extends BeanConverter { + + public BeanConverterForJSON(Type beanType) { + super(beanType); + } + + @Override + protected T convertInternal(final Object value) { + final Class 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); + } +} diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONConverter.java b/hutool-json/src/main/java/cn/hutool/json/JSONConverter.java index 4e91df9bd..46239c4ed 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONConverter.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONConverter.java @@ -28,7 +28,7 @@ public class JSONConverter implements Converter { 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); diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONUtil.java b/hutool-json/src/main/java/cn/hutool/json/JSONUtil.java index 7938ed3c6..027486311 100755 --- a/hutool-json/src/main/java/cn/hutool/json/JSONUtil.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONUtil.java @@ -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; } } diff --git a/hutool-json/src/test/java/Issue2555Test.java b/hutool-json/src/test/java/Issue2555Test.java new file mode 100755 index 000000000..25908b9ab --- /dev/null +++ b/hutool-json/src/test/java/Issue2555Test.java @@ -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 { + @Override + public void serialize(JSONObject json, MyType bean) { + json.set("addr", bean.getAddress()); + } + } + + public static class MyDeserializer implements JSONDeserializer{ + @Override + public MyType deserialize(JSON json) { + final MyType myType = new MyType(); + myType.setAddress(((JSONObject)json).getStr("addr")); + return myType; + } + } +}