1
0
mirror of https://gitee.com/dromara/hutool.git synced 2025-04-05 17:37:59 +08:00

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
CHANGELOG.md
hutool-core/src/main/java/cn/hutool/core
hutool-json/src

View File

@ -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

View File

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

View File

@ -3,6 +3,7 @@ package cn.hutool.core.lang;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import java.util.Map;
@ -192,7 +193,7 @@ public class Assert {
* @since 5.4.5
*/
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();
}
return object;

View File

@ -125,17 +125,17 @@ public class JSONObject implements JSON, JSONGetter<String>, Map<String, Object>
}
final Comparator<String> 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<String>, Map<String, Object>
final JSONWriter jsonWriter = JSONWriter.of(writer, indentFactor, indent, config)
.beginObj();
this.forEach((key, value) -> {
if (null != filter){
if (null != filter) {
final MutablePair<String, Object> pair = new MutablePair<>(key, value);
if (filter.accept(pair)) {
// 使用修改后的键值对

View File

@ -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;
/**
* 全局的序列化和反序列化器映射<br>
* 在JSON和Java对象转换过程中优先使用注册于此处的自定义转换
*
*
* @author Looly
*
*/
public class GlobalSerializeMapping {
private static Map<Type, JSONSerializer<? extends JSON, ?>> serializerMap;
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 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 类型

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 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();