mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-05 17:37:59 +08:00
add TemporalAccessorSerializer
This commit is contained in:
parent
10f65045e3
commit
4b56b545e7
CHANGELOG.md
hutool-core/src/main/java/cn/hutool/core
hutool-json/src
main/java/cn/hutool/json
test/java/cn/hutool/json
@ -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)
|
||||
|
@ -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 时区ID,null表示当前系统默认的时区
|
||||
* @param zoneId 时区ID,null表示当前系统默认的时区
|
||||
* @return java.time中的对象
|
||||
*/
|
||||
private TemporalAccessor parseFromInstant(Instant instant, ZoneId zoneId) {
|
||||
if(Instant.class.equals(this.targetType)){
|
||||
if (Instant.class.equals(this.targetType)) {
|
||||
return instant;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)) {
|
||||
// 使用修改后的键值对
|
||||
|
@ -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 类型
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user