From 4b56b545e750041808713c8a4949aeeaaadc44e5 Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 17 Feb 2022 11:53:57 +0800 Subject: [PATCH] add TemporalAccessorSerializer --- CHANGELOG.md | 3 +- .../impl/TemporalAccessorConverter.java | 38 +++++----- .../main/java/cn/hutool/core/lang/Assert.java | 3 +- .../main/java/cn/hutool/json/JSONObject.java | 10 +-- .../serialize/GlobalSerializeMapping.java | 46 ++++++++---- .../serialize/TemporalAccessorSerializer.java | 75 +++++++++++++++++++ .../java/cn/hutool/json/Issue2090Test.java | 26 +++++++ 7 files changed, 162 insertions(+), 39 deletions(-) create mode 100755 hutool-json/src/main/java/cn/hutool/json/serialize/TemporalAccessorSerializer.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 1566a4239..01e90509c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,13 @@ # 🚀Changelog ------------------------------------------------------------------------------------------------------------- -# 5.7.22 (2022-02-16) +# 5.7.22 (2022-02-17) ### 🐣新特性 * 【poi 】 ExcelUtil.readBySax增加对POI-5.2.0的兼容性(issue#I4TJF4@gitee) * 【extra 】 Ftp增加构造(issue#I4TKXP@gitee) * 【core 】 GenericBuilder支持Map构建(pr#540@Github) +* 【json 】 新增TemporalAccessorSerializer ### 🐞Bug修复 * 【cache 】 修复ReentrantCache.toString方法线程不安全问题(issue#2140@Github) diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/TemporalAccessorConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/TemporalAccessorConverter.java index 22d5186cf..46c5384e8 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/TemporalAccessorConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/TemporalAccessorConverter.java @@ -93,7 +93,7 @@ public class TemporalAccessorConverter extends AbstractConverter T notNull(T object, Supplier errorSupplier) throws X { - if (null == object) { + if (ObjectUtil.isNull(object)) { throw errorSupplier.get(); } return object; diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONObject.java b/hutool-json/src/main/java/cn/hutool/json/JSONObject.java index cff35cd9e..a7d5ddf1e 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONObject.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONObject.java @@ -125,17 +125,17 @@ public class JSONObject implements JSON, JSONGetter, Map } final Comparator keyComparator = config.getKeyComparator(); if (config.isIgnoreCase()) { - if(null != keyComparator){ + if (null != keyComparator) { // 比较器存在情况下,isOrder无效 this.rawHashMap = new CaseInsensitiveTreeMap<>(keyComparator); - }else{ + } else { this.rawHashMap = config.isOrder() ? new CaseInsensitiveLinkedMap<>(capacity) : new CaseInsensitiveMap<>(capacity); } } else { - if(null != keyComparator){ + if (null != keyComparator) { // 比较器存在情况下,isOrder无效 this.rawHashMap = new TreeMap<>(keyComparator); - }else{ + } else { this.rawHashMap = MapUtil.newHashMap(capacity, config.isOrder()); } } @@ -607,7 +607,7 @@ public class JSONObject implements JSON, JSONGetter, Map final JSONWriter jsonWriter = JSONWriter.of(writer, indentFactor, indent, config) .beginObj(); this.forEach((key, value) -> { - if (null != filter){ + if (null != filter) { final MutablePair pair = new MutablePair<>(key, value); if (filter.accept(pair)) { // 使用修改后的键值对 diff --git a/hutool-json/src/main/java/cn/hutool/json/serialize/GlobalSerializeMapping.java b/hutool-json/src/main/java/cn/hutool/json/serialize/GlobalSerializeMapping.java index 01bcad54b..580bf7ed0 100644 --- a/hutool-json/src/main/java/cn/hutool/json/serialize/GlobalSerializeMapping.java +++ b/hutool-json/src/main/java/cn/hutool/json/serialize/GlobalSerializeMapping.java @@ -1,36 +1,56 @@ package cn.hutool.json.serialize; +import cn.hutool.json.JSON; + import java.lang.reflect.Type; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import cn.hutool.json.JSON; - /** * 全局的序列化和反序列化器映射
* 在JSON和Java对象转换过程中,优先使用注册于此处的自定义转换 - * + * * @author Looly * */ public class GlobalSerializeMapping { - + private static Map> serializerMap; private static Map> deserializerMap; - + + static { + serializerMap = new ConcurrentHashMap<>(); + deserializerMap = new ConcurrentHashMap<>(); + + final TemporalAccessorSerializer localDateSerializer = new TemporalAccessorSerializer(LocalDate.class); + serializerMap.put(LocalDate.class, localDateSerializer); + deserializerMap.put(LocalDate.class, localDateSerializer); + + final TemporalAccessorSerializer localDateTimeSerializer = new TemporalAccessorSerializer(LocalDateTime.class); + serializerMap.put(LocalDateTime.class, localDateTimeSerializer); + deserializerMap.put(LocalDateTime.class, localDateTimeSerializer); + + final TemporalAccessorSerializer localTimeSerializer = new TemporalAccessorSerializer(LocalTime.class); + serializerMap.put(LocalTime.class, localTimeSerializer); + deserializerMap.put(LocalTime.class, localTimeSerializer); + } + /** * 加入自定义的序列化器 - * + * * @param type 对象类型 * @param serializer 序列化器实现 */ public static void put(Type type, JSONArraySerializer serializer) { putInternal(type, serializer); } - + /** * 加入自定义的序列化器 - * + * * @param type 对象类型 * @param serializer 序列化器实现 */ @@ -40,7 +60,7 @@ public class GlobalSerializeMapping { /** * 加入自定义的序列化器 - * + * * @param type 对象类型 * @param serializer 序列化器实现 */ @@ -50,10 +70,10 @@ public class GlobalSerializeMapping { } serializerMap.put(type, serializer); } - + /** * 加入自定义的反序列化器 - * + * * @param type 对象类型 * @param deserializer 反序列化器实现 */ @@ -63,7 +83,7 @@ public class GlobalSerializeMapping { } deserializerMap.put(type, deserializer); } - + /** * 获取自定义的序列化器,如果未定义返回{@code null} * @param type 类型 @@ -75,7 +95,7 @@ public class GlobalSerializeMapping { } return serializerMap.get(type); } - + /** * 获取自定义的反序列化器,如果未定义返回{@code null} * @param type 类型 diff --git a/hutool-json/src/main/java/cn/hutool/json/serialize/TemporalAccessorSerializer.java b/hutool-json/src/main/java/cn/hutool/json/serialize/TemporalAccessorSerializer.java new file mode 100755 index 000000000..7ca54d49b --- /dev/null +++ b/hutool-json/src/main/java/cn/hutool/json/serialize/TemporalAccessorSerializer.java @@ -0,0 +1,75 @@ +package cn.hutool.json.serialize; + +import cn.hutool.json.JSON; +import cn.hutool.json.JSONException; +import cn.hutool.json.JSONObject; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.temporal.TemporalAccessor; + +/** + * {@link TemporalAccessor}的JSON自定义序列化实现 + * + * @author looly + * @since 5.7.22 + */ +public class TemporalAccessorSerializer implements JSONObjectSerializer, JSONDeserializer { + + private static final String YEAR_KEY = "year"; + private static final String MONTH_KEY = "month"; + private static final String DAY_KEY = "day"; + private static final String HOUR_KEY = "hour"; + private static final String MINUTE_KEY = "minute"; + private static final String SECOND_KEY = "second"; + private static final String NANO_KEY = "nano"; + + private final Class temporalAccessorClass; + + public TemporalAccessorSerializer(Class temporalAccessorClass) { + this.temporalAccessorClass = temporalAccessorClass; + } + + @Override + public void serialize(JSONObject json, TemporalAccessor bean) { + if (bean instanceof LocalDate) { + final LocalDate localDate = (LocalDate) bean; + json.set(YEAR_KEY, localDate.getYear()); + json.set(MONTH_KEY, localDate.getMonthValue()); + json.set(DAY_KEY, localDate.getDayOfMonth()); + } else if (bean instanceof LocalDateTime) { + final LocalDateTime localDateTime = (LocalDateTime) bean; + json.set(YEAR_KEY, localDateTime.getYear()); + json.set(MONTH_KEY, localDateTime.getMonthValue()); + json.set(DAY_KEY, localDateTime.getDayOfMonth()); + json.set(HOUR_KEY, localDateTime.getHour()); + json.set(MINUTE_KEY, localDateTime.getMinute()); + json.set(SECOND_KEY, localDateTime.getSecond()); + json.set(NANO_KEY, localDateTime.getNano()); + } else if (bean instanceof LocalTime) { + final LocalTime localTime = (LocalTime) bean; + json.set(HOUR_KEY, localTime.getHour()); + json.set(MINUTE_KEY, localTime.getMinute()); + json.set(SECOND_KEY, localTime.getSecond()); + json.set(NANO_KEY, localTime.getNano()); + } else { + throw new JSONException("Unsupported type to JSON: {}", bean.getClass().getName()); + } + } + + @Override + public TemporalAccessor deserialize(JSON json) { + final JSONObject jsonObject = (JSONObject) json; + if (LocalDate.class.equals(this.temporalAccessorClass)) { + return LocalDate.of(jsonObject.getInt(YEAR_KEY), jsonObject.getInt(MONTH_KEY), jsonObject.getInt(DAY_KEY)); + } else if (LocalDateTime.class.equals(this.temporalAccessorClass)) { + return LocalDateTime.of(jsonObject.getInt(YEAR_KEY), jsonObject.getInt(MONTH_KEY), jsonObject.getInt(DAY_KEY), + jsonObject.getInt(HOUR_KEY), jsonObject.getInt(MINUTE_KEY), jsonObject.getInt(SECOND_KEY), jsonObject.getInt(NANO_KEY)); + } else if (LocalTime.class.equals(this.temporalAccessorClass)) { + return LocalTime.of(jsonObject.getInt(HOUR_KEY), jsonObject.getInt(MINUTE_KEY), jsonObject.getInt(SECOND_KEY), jsonObject.getInt(NANO_KEY)); + } + + throw new JSONException("Unsupported type from JSON: {}", this.temporalAccessorClass); + } +} diff --git a/hutool-json/src/test/java/cn/hutool/json/Issue2090Test.java b/hutool-json/src/test/java/cn/hutool/json/Issue2090Test.java index f1f59b68e..de67cb0e8 100755 --- a/hutool-json/src/test/java/cn/hutool/json/Issue2090Test.java +++ b/hutool-json/src/test/java/cn/hutool/json/Issue2090Test.java @@ -5,6 +5,8 @@ import org.junit.Assert; import org.junit.Test; import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.Month; /** @@ -29,6 +31,30 @@ public class Issue2090Test { Assert.assertNotNull(jsonObject.toString()); } + @Test + public void toBeanLocalDateTest(){ + LocalDate d = LocalDate.now(); + final JSONObject obj = JSONUtil.parseObj(d); + LocalDate d2 = obj.toBean(LocalDate.class); + Assert.assertEquals(d, d2); + } + + @Test + public void toBeanLocalDateTimeTest(){ + LocalDateTime d = LocalDateTime.now(); + final JSONObject obj = JSONUtil.parseObj(d); + LocalDateTime d2 = obj.toBean(LocalDateTime.class); + Assert.assertEquals(d, d2); + } + + @Test + public void toBeanLocalTimeTest(){ + LocalTime d = LocalTime.now(); + final JSONObject obj = JSONUtil.parseObj(d); + LocalTime d2 = obj.toBean(LocalTime.class); + Assert.assertEquals(d, d2); + } + @Test public void monthTest(){ final JSONObject jsonObject = new JSONObject();