java-为什么我的DateTime反序列化器会截断DateTime的分钟/秒/毫秒?

我有一个反序列化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());
        }
    }
}

但是,当我输入时,我的反序列化方法是:

2015-07-29T11:00:00.000Z

我收到:

2015-07-29T11

从System.out.println(dateAsString);为什么会截断我的输入?

我认为我的问题在我的测试班内:

我构造了一个与Google的Gson一起使用的DateTime对象.但是,我认为DateTimeType的默认构造函数不支持分钟/秒/毫秒.有没有一种方法可以扩展DateTimeType以支持它?

这是我的测试课:

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().但是,此格式格式为yyyy-MM-dd’T’HH:mm:ss.SSS,如您所见,它不包含时区.您要使用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,其流API为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));
  }
}
上一篇:使用Android Studio反序列化GSON时出现错误


下一篇:java-使用Gson for Restlet将Post数据(表示形式)转换为对象