为什么我的 DateTime 反序列化会截断 DateTimes minute/second/millisecond?
Why is my DateTime deserializer is truncating DateTime's minute/second/millisecond?
我有一个 class 那个 deserializes
一个 JSON
元素。
public class DateTimeConverter implements JsonSerializer<DateTime>, JsonDeserializer<DateTime>
{
private static final DateTimeFormatter DATE_FORMAT = ISODateTimeFormat.dateHourMinuteSecondMillis();
@Override
public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context)
{
final DateTimeFormatter fmt = ISODateTimeFormat.dateHourMinuteSecondMillis();
return new JsonPrimitive(fmt.print(src));
}
@Override
public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException
{
final String dateAsString = json.getAsString();
System.out.println(dateAsString);
if (json.isJsonNull() || dateAsString.length()==0)
{
return null;
}
else
{
return DATE_FORMAT.parseDateTime(json.getAsString());
}
}
}
然而,我的 Deserialize
方法当我输入时:
2015-07-29T11:00:00.000Z
我收到:
2015-07-29T11
来自 System.out.println(dateAsString);
为什么它会截断我的输入?
我认为我的问题在我的测试中 class:
我构建了一个 DateTime
对象与 Google 的 Gson 一起使用。但是,我认为 DateTimeType
的默认构造函数不支持 minute/second/millisecond。有什么方法可以扩展 DateTimeType
来支持它吗?
这是我的测试class:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import org.joda.time.DateTime;
import org.junit.Test;
import java.lang.reflect.Type;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* Tests {@link DateTimeConverter}.
*/
public class DateTimeConverterTest {
String testTime = "2015-07-29T11:00:00.001Z";
@Test
public void testDateTimeConverter() throws Exception {
final Gson gson = initCustomGSON();
Type DateTimeType = new TypeToken<DateTime>() {
}.getType();
System.out.println(testTime);
DateTimeConverter timeConverter = new DateTimeConverter();
DateTime m = (gson.fromJson(testTime, DateTimeType));
assertThat("11", is(m.hourOfDay().getAsText()));
}
public Gson initCustomGSON() {
final GsonBuilder builder = new GsonBuilder();
JodaTimeConverters converter = new JodaTimeConverters();
converter.registerAll(builder);
return builder.create();
}
}
这段代码有一些问题。
您的第一个问题是 :
是 Json 中的运算符。您正在解释其中包含 :
的未转义 String
,因此 Gson 将其解释为 key
: value
。您的测试字符串需要用引号将整个文本日期括起来,以防止发生这种情况,例如
String testTime = "\"2015-07-29T11:00:00.001Z\"";
您使用的是 ISODateTimeFormat.dateHourMinuteSecondMillis()
in your code. However, the format pattern for this is yyyy-MM-dd'T'HH:mm:ss.SSS
, which as you can see does not include a time zone. You want to be using ISODateTimeFormat.dateTime()
,其模式是 yyyy-MM-dd'T'HH:mm:ss.SSSZZ
,它确实有时区。
private static final DateTimeFormatter DATE_FORMAT = ISODateTimeFormat.dateTime();
完成这两项更改后,DateTime
对象终于正确创建了...但它将在 您的 本地时间创建时区,而不是 UTC(它会正确调整您所在时区的时间。您可以通过以下方式轻松将其切换回 UTC:
DateTime m = ((DateTime) (gson.fromJson(testTime, DateTimeType))).withZone(DateTimeZone.UTC);
完成这三项更改后,您的测试就会通过。 但是: 我强烈建议不要使用 JsonSerializer
和 JsonDeserializer
,它们已被弃用,取而代之的是 TypeAdapter
, whose streaming API is significantly more performant:
New applications should prefer TypeAdapter
, whose streaming API is more efficient than this interface's tree API.
我知道用户指南提供了如何使用 JsonSerializer
/ JsonDeserializer
API 执行此操作的代码,但这只是因为他们尚未更新它。
它会像这样:
public class DateTimeAdapter extends TypeAdapter<DateTime> {
private static final DateTimeFormatter FORMAT = ISODateTimeFormat.dateTime();
public DateTime read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
}
String dateString = reader.nextString();
if(dateString.length() == 0) return null;
return FORMAT.parseDateTime(dateString);
}
public void write(JsonWriter writer, DateTime value) throws IOException {
if (value == null) {
writer.nullValue();
return;
}
writer.value(FORMAT.print(value));
}
}
我有一个 class 那个 deserializes
一个 JSON
元素。
public class DateTimeConverter implements JsonSerializer<DateTime>, JsonDeserializer<DateTime>
{
private static final DateTimeFormatter DATE_FORMAT = ISODateTimeFormat.dateHourMinuteSecondMillis();
@Override
public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context)
{
final DateTimeFormatter fmt = ISODateTimeFormat.dateHourMinuteSecondMillis();
return new JsonPrimitive(fmt.print(src));
}
@Override
public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException
{
final String dateAsString = json.getAsString();
System.out.println(dateAsString);
if (json.isJsonNull() || dateAsString.length()==0)
{
return null;
}
else
{
return DATE_FORMAT.parseDateTime(json.getAsString());
}
}
}
然而,我的 Deserialize
方法当我输入时:
2015-07-29T11:00:00.000Z
我收到:
2015-07-29T11
来自 System.out.println(dateAsString);
为什么它会截断我的输入?
我认为我的问题在我的测试中 class:
我构建了一个 DateTime
对象与 Google 的 Gson 一起使用。但是,我认为 DateTimeType
的默认构造函数不支持 minute/second/millisecond。有什么方法可以扩展 DateTimeType
来支持它吗?
这是我的测试class:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import org.joda.time.DateTime;
import org.junit.Test;
import java.lang.reflect.Type;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* Tests {@link DateTimeConverter}.
*/
public class DateTimeConverterTest {
String testTime = "2015-07-29T11:00:00.001Z";
@Test
public void testDateTimeConverter() throws Exception {
final Gson gson = initCustomGSON();
Type DateTimeType = new TypeToken<DateTime>() {
}.getType();
System.out.println(testTime);
DateTimeConverter timeConverter = new DateTimeConverter();
DateTime m = (gson.fromJson(testTime, DateTimeType));
assertThat("11", is(m.hourOfDay().getAsText()));
}
public Gson initCustomGSON() {
final GsonBuilder builder = new GsonBuilder();
JodaTimeConverters converter = new JodaTimeConverters();
converter.registerAll(builder);
return builder.create();
}
}
这段代码有一些问题。
您的第一个问题是
:
是 Json 中的运算符。您正在解释其中包含:
的未转义String
,因此 Gson 将其解释为key
:value
。您的测试字符串需要用引号将整个文本日期括起来,以防止发生这种情况,例如String testTime = "\"2015-07-29T11:00:00.001Z\"";
您使用的是
ISODateTimeFormat.dateHourMinuteSecondMillis()
in your code. However, the format pattern for this isyyyy-MM-dd'T'HH:mm:ss.SSS
, which as you can see does not include a time zone. You want to be usingISODateTimeFormat.dateTime()
,其模式是yyyy-MM-dd'T'HH:mm:ss.SSSZZ
,它确实有时区。private static final DateTimeFormatter DATE_FORMAT = ISODateTimeFormat.dateTime();
完成这两项更改后,
DateTime
对象终于正确创建了...但它将在 您的 本地时间创建时区,而不是 UTC(它会正确调整您所在时区的时间。您可以通过以下方式轻松将其切换回 UTC:DateTime m = ((DateTime) (gson.fromJson(testTime, DateTimeType))).withZone(DateTimeZone.UTC);
完成这三项更改后,您的测试就会通过。 但是: 我强烈建议不要使用 JsonSerializer
和 JsonDeserializer
,它们已被弃用,取而代之的是 TypeAdapter
, whose streaming API is significantly more performant:
New applications should prefer
TypeAdapter
, whose streaming API is more efficient than this interface's tree API.
我知道用户指南提供了如何使用 JsonSerializer
/ JsonDeserializer
API 执行此操作的代码,但这只是因为他们尚未更新它。
它会像这样:
public class DateTimeAdapter extends TypeAdapter<DateTime> {
private static final DateTimeFormatter FORMAT = ISODateTimeFormat.dateTime();
public DateTime read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
}
String dateString = reader.nextString();
if(dateString.length() == 0) return null;
return FORMAT.parseDateTime(dateString);
}
public void write(JsonWriter writer, DateTime value) throws IOException {
if (value == null) {
writer.nullValue();
return;
}
writer.value(FORMAT.print(value));
}
}