feat(gson): 新增 InstantTypeAdapter
用于 Gson 序列化和反序列化 Instant
`InstantTypeAdapter` 用于 Gson 通过 `DateTimeFormatter#ISO_INSTANT` 序列化和反序列化 `Instant` 类型。
This commit is contained in:
parent
2e73ca5f6d
commit
2827f69aef
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2025 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package xyz.zhouxy.plusone.commons.gson;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
import com.google.gson.TypeAdapter;
|
||||||
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code Instant} 的 {@code TypeAdapter},
|
||||||
|
* 用于 Gson 对 {@code Instant} 进行相互转换。
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 使用 {@link DateTimeFormatter#ISO_INSTANT} 进行 {@link Instant} 的序列化与反序列化。
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||||
|
* @since 1.1.0
|
||||||
|
* @see TypeAdapter
|
||||||
|
* @see com.google.gson.GsonBuilder
|
||||||
|
*/
|
||||||
|
public final class InstantTypeAdapter extends TypeAdapter<Instant> {
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public void write(JsonWriter out, Instant value) throws IOException {
|
||||||
|
out.value(DateTimeFormatter.ISO_INSTANT.format(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public Instant read(JsonReader in) throws IOException {
|
||||||
|
return Instant.parse(in.nextString());
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,7 @@ package xyz.zhouxy.plusone.commons.gson;
|
|||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
@ -25,6 +26,7 @@ import java.time.format.DateTimeFormatter;
|
|||||||
import java.time.format.DateTimeFormatterBuilder;
|
import java.time.format.DateTimeFormatterBuilder;
|
||||||
import java.time.temporal.ChronoField;
|
import java.time.temporal.ChronoField;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
@ -39,6 +41,7 @@ public class GsonTypeAdapterTests {
|
|||||||
.registerTypeAdapter(LocalDate.class, new LocalDateTypeAdapter().nullSafe())
|
.registerTypeAdapter(LocalDate.class, new LocalDateTypeAdapter().nullSafe())
|
||||||
.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeTypeAdapter().nullSafe())
|
.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeTypeAdapter().nullSafe())
|
||||||
.registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeTypeAdapter().nullSafe())
|
.registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeTypeAdapter().nullSafe())
|
||||||
|
.registerTypeAdapter(Instant.class, new InstantTypeAdapter().nullSafe())
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
|
final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
|
||||||
@ -60,24 +63,29 @@ public class GsonTypeAdapterTests {
|
|||||||
final LocalDate date = LocalDate.of(2025, 6, 6);
|
final LocalDate date = LocalDate.of(2025, 6, 6);
|
||||||
final LocalDateTime localDateTime = date.atTime(6, 6, 6, 666000000);
|
final LocalDateTime localDateTime = date.atTime(6, 6, 6, 666000000);
|
||||||
final ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("+08:00"));
|
final ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("+08:00"));
|
||||||
|
final Instant instant = zonedDateTime.toInstant();
|
||||||
|
|
||||||
|
@DisplayName("测试使用 TypeAdapter 中默认的 formatter 进行序列化")
|
||||||
@Test
|
@Test
|
||||||
void test_serialize_defaultFormatter() {
|
void test_serialize_defaultFormatter() {
|
||||||
Foo foo = new Foo();
|
Foo foo = new Foo();
|
||||||
foo.localDate = date;
|
foo.localDate = date;
|
||||||
foo.localDateTime = localDateTime;
|
foo.localDateTime = localDateTime;
|
||||||
foo.zonedDateTime = zonedDateTime;
|
foo.zonedDateTime = zonedDateTime;
|
||||||
|
foo.instant = instant;
|
||||||
|
|
||||||
String json = String.format(
|
String json = String.format(
|
||||||
"{\"localDate\":\"%s\",\"localDateTime\":\"%s\",\"zonedDateTime\":\"%s\"}",
|
"{\"localDate\":\"%s\",\"localDateTime\":\"%s\",\"zonedDateTime\":\"%s\",\"instant\":\"%s\"}",
|
||||||
DateTimeFormatter.ISO_LOCAL_DATE.format(date),
|
DateTimeFormatter.ISO_LOCAL_DATE.format(date),
|
||||||
DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(localDateTime),
|
DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(localDateTime),
|
||||||
DateTimeFormatter.ISO_ZONED_DATE_TIME.format(zonedDateTime)
|
DateTimeFormatter.ISO_ZONED_DATE_TIME.format(zonedDateTime),
|
||||||
|
DateTimeFormatter.ISO_INSTANT.format(instant)
|
||||||
);
|
);
|
||||||
|
|
||||||
assertEquals(json, gsonWithDefaultFormatter.toJson(foo));
|
assertEquals(json, gsonWithDefaultFormatter.toJson(foo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DisplayName("测试指定 formatter 进行序列化")
|
||||||
@Test
|
@Test
|
||||||
void test_serialize_specifiedFormatter() {
|
void test_serialize_specifiedFormatter() {
|
||||||
Foo foo = new Foo();
|
Foo foo = new Foo();
|
||||||
@ -95,20 +103,24 @@ public class GsonTypeAdapterTests {
|
|||||||
assertEquals(json, gsonWithSpecifiedFormatter.toJson(foo));
|
assertEquals(json, gsonWithSpecifiedFormatter.toJson(foo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DisplayName("测试使用 TypeAdapter 中默认的 formatter 进行反序列化")
|
||||||
@Test
|
@Test
|
||||||
void test_deserialize_defaultFormatter() {
|
void test_deserialize_defaultFormatter() {
|
||||||
String json = String.format(
|
String json = String.format(
|
||||||
"{\"localDate\":\"%s\",\"localDateTime\":\"%s\",\"zonedDateTime\":\"%s\"}",
|
"{\"localDate\":\"%s\",\"localDateTime\":\"%s\",\"zonedDateTime\":\"%s\",\"instant\":\"%s\"}",
|
||||||
DateTimeFormatter.ISO_LOCAL_DATE.format(date),
|
DateTimeFormatter.ISO_LOCAL_DATE.format(date),
|
||||||
DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(localDateTime),
|
DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(localDateTime),
|
||||||
DateTimeFormatter.ISO_ZONED_DATE_TIME.format(zonedDateTime)
|
DateTimeFormatter.ISO_ZONED_DATE_TIME.format(zonedDateTime),
|
||||||
|
DateTimeFormatter.ISO_INSTANT.format(instant)
|
||||||
);
|
);
|
||||||
Foo foo = gsonWithDefaultFormatter.fromJson(json, Foo.class);
|
Foo foo = gsonWithDefaultFormatter.fromJson(json, Foo.class);
|
||||||
assertEquals(date, foo.localDate);
|
assertEquals(date, foo.localDate);
|
||||||
assertEquals(localDateTime, foo.localDateTime);
|
assertEquals(localDateTime, foo.localDateTime);
|
||||||
assertEquals(zonedDateTime, foo.zonedDateTime);
|
assertEquals(zonedDateTime, foo.zonedDateTime);
|
||||||
|
assertEquals(instant, foo.instant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DisplayName("测试指定 formatter 进行反序列化")
|
||||||
@Test
|
@Test
|
||||||
void test_deserialize_specifiedFormatter() {
|
void test_deserialize_specifiedFormatter() {
|
||||||
String json = String.format(
|
String json = String.format(
|
||||||
@ -127,5 +139,6 @@ public class GsonTypeAdapterTests {
|
|||||||
LocalDate localDate;
|
LocalDate localDate;
|
||||||
LocalDateTime localDateTime;
|
LocalDateTime localDateTime;
|
||||||
ZonedDateTime zonedDateTime;
|
ZonedDateTime zonedDateTime;
|
||||||
|
Instant instant;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user