From df726654afbb2e660a49192c7ca73a687a9466d0 Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 8 Aug 2021 21:36:37 +0800 Subject: [PATCH] add JSONBeanParser --- CHANGELOG.md | 1 + .../java/cn/hutool/core/date/DateRange.java | 6 +-- .../java/cn/hutool/json/JSONBeanParser.java | 18 +++++++ .../java/cn/hutool/json/JSONConverter.java | 25 ++++++++-- .../main/java/cn/hutool/json/JSONString.java | 4 +- .../main/java/cn/hutool/json/JSONSupport.java | 29 +++++++---- .../java/cn/hutool/json/IssuesI44E4HTest.java | 48 +++++++++++++++++++ .../cn/hutool/json/JSONBeanParserTest.java | 30 ++++++++++++ 8 files changed, 143 insertions(+), 18 deletions(-) create mode 100755 hutool-json/src/main/java/cn/hutool/json/JSONBeanParser.java create mode 100755 hutool-json/src/test/java/cn/hutool/json/IssuesI44E4HTest.java create mode 100755 hutool-json/src/test/java/cn/hutool/json/JSONBeanParserTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index fb36e430f..a4ee8a698 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ * 【core 】 MapProxy支持return this的setter方法(pr#392@Gitee) * 【core 】 BeeDSFactory移除sqlite事务修复代码,新版本BeeCP已修复 * 【core 】 增加compress包,扩充Zip操作灵活性 +* 【json 】 增加JSONBeanParser ### 🐞Bug修复 * 【core 】 改进NumberChineseFormatter算法,补充完整单元测试,解决零问题 diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateRange.java b/hutool-core/src/main/java/cn/hutool/core/date/DateRange.java index ca8aa084a..0e91132a4 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateRange.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateRange.java @@ -20,7 +20,7 @@ public class DateRange extends Range { * @param end 结束日期时间(包括) * @param unit 步进单位 */ - public DateRange(Date start, Date end, final DateField unit) { + public DateRange(Date start, Date end, DateField unit) { this(start, end, unit, 1); } @@ -32,7 +32,7 @@ public class DateRange extends Range { * @param unit 步进单位 * @param step 步进数 */ - public DateRange(Date start, Date end, final DateField unit, final int step) { + public DateRange(Date start, Date end, DateField unit, int step) { this(start, end, unit, step, true, true); } @@ -46,7 +46,7 @@ public class DateRange extends Range { * @param isIncludeStart 是否包含开始的时间 * @param isIncludeEnd 是否包含结束的时间 */ - public DateRange(Date start, Date end, final DateField unit, final int step, boolean isIncludeStart, boolean isIncludeEnd) { + public DateRange(Date start, Date end, DateField unit, int step, boolean isIncludeStart, boolean isIncludeEnd) { super(DateUtil.date(start), DateUtil.date(end), (current, end1, index) -> { final DateTime dt = DateUtil.date(start).offsetNew(unit, (index + 1) * step); if (dt.isAfter(end1)) { diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONBeanParser.java b/hutool-json/src/main/java/cn/hutool/json/JSONBeanParser.java new file mode 100755 index 000000000..6c9c1212a --- /dev/null +++ b/hutool-json/src/main/java/cn/hutool/json/JSONBeanParser.java @@ -0,0 +1,18 @@ +package cn.hutool.json; + +/** + * 实现此接口的类可以通过实现{@code parse(value)}方法来将JSON中的值解析为此对象的值 + * + * @author Looly + * @since 5.7.8 + */ +public interface JSONBeanParser { + + /** + * value转Bean
+ * 通过实现此接口,将JSON中的值填充到当前对象的字段值中,即对象自行实现JSON反序列化逻辑 + * + * @param value 被解析的对象类型,可能为JSON或者普通String、Number等 + */ + void parse(T 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 d264929d9..222f7a9a4 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONConverter.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONConverter.java @@ -6,6 +6,7 @@ import cn.hutool.core.convert.Converter; import cn.hutool.core.convert.ConverterRegistry; import cn.hutool.core.convert.impl.ArrayConverter; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.TypeUtil; import cn.hutool.json.serialize.GlobalSerializeMapping; @@ -16,7 +17,7 @@ import java.util.List; /** * JSON转换器 - * + * * @author looly * @since 4.2.2 */ @@ -32,7 +33,7 @@ public class JSONConverter implements Converter { /** * JSONArray转数组 - * + * * @param jsonArray JSONArray * @param arrayClass 数组元素类型 * @return 数组对象 @@ -43,7 +44,7 @@ public class JSONConverter implements Converter { /** * 将JSONArray转换为指定类型的对量列表 - * + * * @param 元素类型 * @param jsonArray JSONArray * @param elementType 对象元素类型 @@ -69,7 +70,21 @@ public class JSONConverter implements Converter { if (JSONUtil.isNull(value)) { return null; } - + + // since 5.7.8,增加自定义Bean反序列化接口 + if(targetType instanceof Class){ + final Class clazz = (Class) targetType; + if (JSONBeanParser.class.isAssignableFrom(clazz)){ + @SuppressWarnings("rawtypes") + JSONBeanParser target = (JSONBeanParser) ReflectUtil.newInstanceIfPossible(clazz); + if(null == target){ + throw new ConvertException("Can not instance [{}]", targetType); + } + target.parse(value); + return (T) target; + } + } + if(value instanceof JSON) { final JSONDeserializer deserializer = GlobalSerializeMapping.getDeserializer(targetType); if(null != deserializer) { @@ -85,7 +100,7 @@ public class JSONConverter implements Converter { // 此处特殊处理,认为返回null属于正常情况 return null; } - + throw new ConvertException("Can not convert {} to type {}", value, ObjectUtil.defaultIfNull(TypeUtil.getClass(targetType), targetType)); } diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONString.java b/hutool-json/src/main/java/cn/hutool/json/JSONString.java index 1d07078c3..05cedf916 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONString.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONString.java @@ -3,7 +3,7 @@ package cn.hutool.json; /** * {@code JSONString}接口定义了一个{@code toJSONString()}
* 实现此接口的类可以通过实现{@code toJSONString()}方法来改变转JSON字符串的方式。 - * + * * @author Looly * */ @@ -11,7 +11,7 @@ public interface JSONString { /** * 自定义转JSON字符串的方法 - * + * * @return JSON字符串 */ String toJSONString(); diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONSupport.java b/hutool-json/src/main/java/cn/hutool/json/JSONSupport.java index 0c15f7360..be4197dcd 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONSupport.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONSupport.java @@ -1,20 +1,33 @@ package cn.hutool.json; +import cn.hutool.core.bean.BeanUtil; + /** * JSON支持
* 继承此类实现实体类与JSON的相互转换 - * - * @author Looly * + * @author Looly */ -public class JSONSupport implements JSONString{ - +public class JSONSupport implements JSONString, JSONBeanParser { + /** * JSON String转Bean + * * @param jsonString JSON String */ - public void parse(String jsonString){ - new JSONObject(jsonString).toBean(this.getClass()); + public void parse(String jsonString) { + parse(new JSONObject(jsonString)); + } + + /** + * JSON String转Bean + * + * @param json JSON String + */ + @Override + public void parse(JSON json) { + final JSONSupport support = json.toBean(this.getClass()); + BeanUtil.copyProperties(support, this); } /** @@ -23,7 +36,7 @@ public class JSONSupport implements JSONString{ public JSONObject toJSON() { return new JSONObject(this); } - + @Override public String toJSONString() { return toJSON().toString(); @@ -31,7 +44,7 @@ public class JSONSupport implements JSONString{ /** * 美化的JSON(使用回车缩进显示JSON),用于打印输出debug - * + * * @return 美化的JSON */ public String toPrettyString() { diff --git a/hutool-json/src/test/java/cn/hutool/json/IssuesI44E4HTest.java b/hutool-json/src/test/java/cn/hutool/json/IssuesI44E4HTest.java new file mode 100755 index 000000000..486b270d2 --- /dev/null +++ b/hutool-json/src/test/java/cn/hutool/json/IssuesI44E4HTest.java @@ -0,0 +1,48 @@ +package cn.hutool.json; + +import cn.hutool.json.serialize.GlobalSerializeMapping; +import cn.hutool.json.serialize.JSONDeserializer; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import org.junit.Assert; +import org.junit.Test; + +/** + * 测试自定义反序列化 + */ +public class IssuesI44E4HTest { + + @Test + public void deserializerTest(){ + GlobalSerializeMapping.put(TestDto.class, (JSONDeserializer) json -> { + final TestDto testDto = new TestDto(); + testDto.setMd(new AcBizModuleMd("name1", ((JSONObject)json).getStr("md"))); + return testDto; + }); + + String jsonStr = "{\"md\":\"value1\"}"; + final TestDto testDto = JSONUtil.toBean(jsonStr, TestDto.class); + Assert.assertEquals("value1", testDto.getMd().getValue()); + } + + @Getter + @Setter + @AllArgsConstructor + public static class AcBizModuleMd { + private String name; + private String value; + // 值列表 + public static final AcBizModuleMd Value1 = new AcBizModuleMd("value1", "name1"); + public static final AcBizModuleMd Value2 = new AcBizModuleMd("value2", "name2"); + public static final AcBizModuleMd Value3 = new AcBizModuleMd("value3", "name3"); + } + + @Getter + @Setter + public static class TestDto { + private AcBizModuleMd md; + } +} + + diff --git a/hutool-json/src/test/java/cn/hutool/json/JSONBeanParserTest.java b/hutool-json/src/test/java/cn/hutool/json/JSONBeanParserTest.java new file mode 100755 index 000000000..0fdce9bb4 --- /dev/null +++ b/hutool-json/src/test/java/cn/hutool/json/JSONBeanParserTest.java @@ -0,0 +1,30 @@ +package cn.hutool.json; + +import lombok.Data; +import org.junit.Assert; +import org.junit.Test; + +public class JSONBeanParserTest { + + @Test + public void parseTest(){ + String jsonStr = "{\"customName\": \"customValue\", \"customAddress\": \"customAddressValue\"}"; + final TestBean testBean = JSONUtil.toBean(jsonStr, TestBean.class); + Assert.assertNotNull(testBean); + Assert.assertEquals("customValue", testBean.getName()); + Assert.assertEquals("customAddressValue", testBean.getAddress()); + } + + @Data + static class TestBean implements JSONBeanParser{ + + private String name; + private String address; + + @Override + public void parse(JSONObject value) { + this.name = value.getStr("customName"); + this.address = value.getStr("customAddress"); + } + } +}