add TemporalAccessorSerializer

This commit is contained in:
Looly 2022-02-17 11:53:57 +08:00
parent 10f65045e3
commit 4b56b545e7
7 changed files with 162 additions and 39 deletions

View File

@ -2,12 +2,13 @@
# 🚀Changelog # 🚀Changelog
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
# 5.7.22 (2022-02-16) # 5.7.22 (2022-02-17)
### 🐣新特性 ### 🐣新特性
* 【poi 】 ExcelUtil.readBySax增加对POI-5.2.0的兼容性issue#I4TJF4@gitee * 【poi 】 ExcelUtil.readBySax增加对POI-5.2.0的兼容性issue#I4TJF4@gitee
* 【extra 】 Ftp增加构造issue#I4TKXP@gitee * 【extra 】 Ftp增加构造issue#I4TKXP@gitee
* 【core 】 GenericBuilder支持Map构建pr#540@Github * 【core 】 GenericBuilder支持Map构建pr#540@Github
* 【json 】 新增TemporalAccessorSerializer
### 🐞Bug修复 ### 🐞Bug修复
* 【cache 】 修复ReentrantCache.toString方法线程不安全问题issue#2140@Github * 【cache 】 修复ReentrantCache.toString方法线程不安全问题issue#2140@Github

View File

@ -93,7 +93,7 @@ public class TemporalAccessorConverter extends AbstractConverter<TemporalAccesso
} else if (value instanceof Date) { } else if (value instanceof Date) {
final DateTime dateTime = DateUtil.date((Date) value); final DateTime dateTime = DateUtil.date((Date) value);
return parseFromInstant(dateTime.toInstant(), dateTime.getZoneId()); return parseFromInstant(dateTime.toInstant(), dateTime.getZoneId());
}else if (value instanceof Calendar) { } else if (value instanceof Calendar) {
final Calendar calendar = (Calendar) value; final Calendar calendar = (Calendar) value;
return parseFromInstant(calendar.toInstant(), calendar.getTimeZone().toZoneId()); return parseFromInstant(calendar.toInstant(), calendar.getTimeZone().toZoneId());
} else { } else {
@ -108,7 +108,7 @@ public class TemporalAccessorConverter extends AbstractConverter<TemporalAccesso
* @return 日期对象 * @return 日期对象
*/ */
private TemporalAccessor parseFromCharSequence(CharSequence value) { private TemporalAccessor parseFromCharSequence(CharSequence value) {
if(StrUtil.isBlank(value)){ if (StrUtil.isBlank(value)) {
return null; return null;
} }
@ -144,13 +144,13 @@ public class TemporalAccessorConverter extends AbstractConverter<TemporalAccesso
*/ */
private TemporalAccessor parseFromTemporalAccessor(TemporalAccessor temporalAccessor) { private TemporalAccessor parseFromTemporalAccessor(TemporalAccessor temporalAccessor) {
TemporalAccessor result = null; TemporalAccessor result = null;
if(temporalAccessor instanceof LocalDateTime){ if (temporalAccessor instanceof LocalDateTime) {
result = parseFromLocalDateTime((LocalDateTime) temporalAccessor); result = parseFromLocalDateTime((LocalDateTime) temporalAccessor);
} else if(temporalAccessor instanceof ZonedDateTime){ } else if (temporalAccessor instanceof ZonedDateTime) {
result = parseFromZonedDateTime((ZonedDateTime) temporalAccessor); result = parseFromZonedDateTime((ZonedDateTime) temporalAccessor);
} }
if(null == result){ if (null == result) {
result = parseFromInstant(DateUtil.toInstant(temporalAccessor), null); result = parseFromInstant(DateUtil.toInstant(temporalAccessor), null);
} }
@ -164,22 +164,22 @@ public class TemporalAccessorConverter extends AbstractConverter<TemporalAccesso
* @return java.time中的对象 * @return java.time中的对象
*/ */
private TemporalAccessor parseFromLocalDateTime(LocalDateTime localDateTime) { private TemporalAccessor parseFromLocalDateTime(LocalDateTime localDateTime) {
if(Instant.class.equals(this.targetType)){ if (Instant.class.equals(this.targetType)) {
return DateUtil.toInstant(localDateTime); return DateUtil.toInstant(localDateTime);
} }
if(LocalDate.class.equals(this.targetType)){ if (LocalDate.class.equals(this.targetType)) {
return localDateTime.toLocalDate(); return localDateTime.toLocalDate();
} }
if(LocalTime.class.equals(this.targetType)){ if (LocalTime.class.equals(this.targetType)) {
return localDateTime.toLocalTime(); return localDateTime.toLocalTime();
} }
if(ZonedDateTime.class.equals(this.targetType)){ if (ZonedDateTime.class.equals(this.targetType)) {
return localDateTime.atZone(ZoneId.systemDefault()); return localDateTime.atZone(ZoneId.systemDefault());
} }
if(OffsetDateTime.class.equals(this.targetType)){ if (OffsetDateTime.class.equals(this.targetType)) {
return localDateTime.atZone(ZoneId.systemDefault()).toOffsetDateTime(); return localDateTime.atZone(ZoneId.systemDefault()).toOffsetDateTime();
} }
if(OffsetTime.class.equals(this.targetType)){ if (OffsetTime.class.equals(this.targetType)) {
return localDateTime.atZone(ZoneId.systemDefault()).toOffsetDateTime().toOffsetTime(); return localDateTime.atZone(ZoneId.systemDefault()).toOffsetDateTime().toOffsetTime();
} }
@ -193,22 +193,22 @@ public class TemporalAccessorConverter extends AbstractConverter<TemporalAccesso
* @return java.time中的对象 * @return java.time中的对象
*/ */
private TemporalAccessor parseFromZonedDateTime(ZonedDateTime zonedDateTime) { private TemporalAccessor parseFromZonedDateTime(ZonedDateTime zonedDateTime) {
if(Instant.class.equals(this.targetType)){ if (Instant.class.equals(this.targetType)) {
return DateUtil.toInstant(zonedDateTime); return DateUtil.toInstant(zonedDateTime);
} }
if(LocalDateTime.class.equals(this.targetType)){ if (LocalDateTime.class.equals(this.targetType)) {
return zonedDateTime.toLocalDateTime(); return zonedDateTime.toLocalDateTime();
} }
if(LocalDate.class.equals(this.targetType)){ if (LocalDate.class.equals(this.targetType)) {
return zonedDateTime.toLocalDate(); return zonedDateTime.toLocalDate();
} }
if(LocalTime.class.equals(this.targetType)){ if (LocalTime.class.equals(this.targetType)) {
return zonedDateTime.toLocalTime(); return zonedDateTime.toLocalTime();
} }
if(OffsetDateTime.class.equals(this.targetType)){ if (OffsetDateTime.class.equals(this.targetType)) {
return zonedDateTime.toOffsetDateTime(); return zonedDateTime.toOffsetDateTime();
} }
if(OffsetTime.class.equals(this.targetType)){ if (OffsetTime.class.equals(this.targetType)) {
return zonedDateTime.toOffsetDateTime().toOffsetTime(); return zonedDateTime.toOffsetDateTime().toOffsetTime();
} }
@ -219,11 +219,11 @@ public class TemporalAccessorConverter extends AbstractConverter<TemporalAccesso
* 将TemporalAccessor型时间戳转换为java.time中的对象 * 将TemporalAccessor型时间戳转换为java.time中的对象
* *
* @param instant {@link Instant}对象 * @param instant {@link Instant}对象
* @param zoneId 时区IDnull表示当前系统默认的时区 * @param zoneId 时区IDnull表示当前系统默认的时区
* @return java.time中的对象 * @return java.time中的对象
*/ */
private TemporalAccessor parseFromInstant(Instant instant, ZoneId zoneId) { private TemporalAccessor parseFromInstant(Instant instant, ZoneId zoneId) {
if(Instant.class.equals(this.targetType)){ if (Instant.class.equals(this.targetType)) {
return instant; return instant;
} }

View File

@ -3,6 +3,7 @@ package cn.hutool.core.lang;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import java.util.Map; import java.util.Map;
@ -192,7 +193,7 @@ public class Assert {
* @since 5.4.5 * @since 5.4.5
*/ */
public static <T, X extends Throwable> T notNull(T object, Supplier<X> errorSupplier) throws X { public static <T, X extends Throwable> T notNull(T object, Supplier<X> errorSupplier) throws X {
if (null == object) { if (ObjectUtil.isNull(object)) {
throw errorSupplier.get(); throw errorSupplier.get();
} }
return object; return object;

View File

@ -125,17 +125,17 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
} }
final Comparator<String> keyComparator = config.getKeyComparator(); final Comparator<String> keyComparator = config.getKeyComparator();
if (config.isIgnoreCase()) { if (config.isIgnoreCase()) {
if(null != keyComparator){ if (null != keyComparator) {
// 比较器存在情况下isOrder无效 // 比较器存在情况下isOrder无效
this.rawHashMap = new CaseInsensitiveTreeMap<>(keyComparator); this.rawHashMap = new CaseInsensitiveTreeMap<>(keyComparator);
}else{ } else {
this.rawHashMap = config.isOrder() ? new CaseInsensitiveLinkedMap<>(capacity) : new CaseInsensitiveMap<>(capacity); this.rawHashMap = config.isOrder() ? new CaseInsensitiveLinkedMap<>(capacity) : new CaseInsensitiveMap<>(capacity);
} }
} else { } else {
if(null != keyComparator){ if (null != keyComparator) {
// 比较器存在情况下isOrder无效 // 比较器存在情况下isOrder无效
this.rawHashMap = new TreeMap<>(keyComparator); this.rawHashMap = new TreeMap<>(keyComparator);
}else{ } else {
this.rawHashMap = MapUtil.newHashMap(capacity, config.isOrder()); this.rawHashMap = MapUtil.newHashMap(capacity, config.isOrder());
} }
} }
@ -607,7 +607,7 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
final JSONWriter jsonWriter = JSONWriter.of(writer, indentFactor, indent, config) final JSONWriter jsonWriter = JSONWriter.of(writer, indentFactor, indent, config)
.beginObj(); .beginObj();
this.forEach((key, value) -> { this.forEach((key, value) -> {
if (null != filter){ if (null != filter) {
final MutablePair<String, Object> pair = new MutablePair<>(key, value); final MutablePair<String, Object> pair = new MutablePair<>(key, value);
if (filter.accept(pair)) { if (filter.accept(pair)) {
// 使用修改后的键值对 // 使用修改后的键值对

View File

@ -1,36 +1,56 @@
package cn.hutool.json.serialize; package cn.hutool.json.serialize;
import cn.hutool.json.JSON;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import cn.hutool.json.JSON;
/** /**
* 全局的序列化和反序列化器映射<br> * 全局的序列化和反序列化器映射<br>
* 在JSON和Java对象转换过程中优先使用注册于此处的自定义转换 * 在JSON和Java对象转换过程中优先使用注册于此处的自定义转换
* *
* @author Looly * @author Looly
* *
*/ */
public class GlobalSerializeMapping { public class GlobalSerializeMapping {
private static Map<Type, JSONSerializer<? extends JSON, ?>> serializerMap; private static Map<Type, JSONSerializer<? extends JSON, ?>> serializerMap;
private static Map<Type, JSONDeserializer<?>> deserializerMap; private static Map<Type, JSONDeserializer<?>> 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 type 对象类型
* @param serializer 序列化器实现 * @param serializer 序列化器实现
*/ */
public static void put(Type type, JSONArraySerializer<?> serializer) { public static void put(Type type, JSONArraySerializer<?> serializer) {
putInternal(type, serializer); putInternal(type, serializer);
} }
/** /**
* 加入自定义的序列化器 * 加入自定义的序列化器
* *
* @param type 对象类型 * @param type 对象类型
* @param serializer 序列化器实现 * @param serializer 序列化器实现
*/ */
@ -40,7 +60,7 @@ public class GlobalSerializeMapping {
/** /**
* 加入自定义的序列化器 * 加入自定义的序列化器
* *
* @param type 对象类型 * @param type 对象类型
* @param serializer 序列化器实现 * @param serializer 序列化器实现
*/ */
@ -50,10 +70,10 @@ public class GlobalSerializeMapping {
} }
serializerMap.put(type, serializer); serializerMap.put(type, serializer);
} }
/** /**
* 加入自定义的反序列化器 * 加入自定义的反序列化器
* *
* @param type 对象类型 * @param type 对象类型
* @param deserializer 反序列化器实现 * @param deserializer 反序列化器实现
*/ */
@ -63,7 +83,7 @@ public class GlobalSerializeMapping {
} }
deserializerMap.put(type, deserializer); deserializerMap.put(type, deserializer);
} }
/** /**
* 获取自定义的序列化器如果未定义返回{@code null} * 获取自定义的序列化器如果未定义返回{@code null}
* @param type 类型 * @param type 类型
@ -75,7 +95,7 @@ public class GlobalSerializeMapping {
} }
return serializerMap.get(type); return serializerMap.get(type);
} }
/** /**
* 获取自定义的反序列化器如果未定义返回{@code null} * 获取自定义的反序列化器如果未定义返回{@code null}
* @param type 类型 * @param type 类型

View File

@ -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<TemporalAccessor>, JSONDeserializer<TemporalAccessor> {
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<? extends TemporalAccessor> temporalAccessorClass;
public TemporalAccessorSerializer(Class<? extends TemporalAccessor> 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);
}
}

View File

@ -5,6 +5,8 @@ import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month; import java.time.Month;
/** /**
@ -29,6 +31,30 @@ public class Issue2090Test {
Assert.assertNotNull(jsonObject.toString()); 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 @Test
public void monthTest(){ public void monthTest(){
final JSONObject jsonObject = new JSONObject(); final JSONObject jsonObject = new JSONObject();