Java 8日期时间序列化和Jackson JSR 310



我在Spring Boot应用程序中使用Java 8 DateTime和Jackson jsr 310支持。

我禁用了SerializationFeature。WRITE_DATES_AS_TIMESTAMPS强制Jackson将localDatetime序列化为字符串而不是int数组。

但是我发现一个奇怪的格式问题,当日期时间微秒或非秒结束0。我认为序列化的结果可能等于date.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),但事实并非如此,format方法省略了零。

完整的示例测试代码。

private LocalDateTime date;
private OffsetDateTime offsetDate;
private ZonedDateTime zonedDate;
@Before
public void setup() throws ServletException {
    date = LocalDateTime.of(2015, 8, 15, 11, 40, 10, 100_000_000);
    offsetDate = OffsetDateTime.of(2015, 8, 15, 11, 40, 10, 100_000_000, ZoneOffset.ofHours(8));
    zonedDate = ZonedDateTime.of(2015, 8, 15, 11, 40, 10, 100_000_000, ZoneId.of("Asia/Shanghai"));
}
@Test
public void testDateFormat() throws Exception {
    Map<String, Object> map = new HashMap<>();
    map.put("localDate", date);
    map.put("offsetDate", offsetDate);
    map.put("zonedDate", zonedDate);
    String json = objectMapper.writeValueAsString(map);
    log.debug("converted json result @" + json);
    JsonNode rootNode = objectMapper.readTree(json);
    JsonNode localDateNode = rootNode.get("localDate");
    assertEquals("local date should be equals", date.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME), localDateNode.textValue());
    JsonNode offsetDateNode = rootNode.get("offsetDate");
    assertEquals("offsetDate date should be equals", offsetDate.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME), offsetDateNode.textValue());
    JsonNode zonedDateNode = rootNode.get("zonedDate");
    assertEquals("zonedDate date should be equals", zonedDate.format(DateTimeFormatter.ISO_ZONED_DATE_TIME), zonedDateNode.textValue());
}

测试失败,日志调试打印

{
    "zonedDate":"2015-08-15T11:40:10.100+08:00[Asia/Shanghai]",
    "localDate":"2015-08-15T11:40:10.100",
    "offsetDate":"2015-08-15T11:40:10.1+08:00"
}

zonedDatelocalDate微秒以00结束,但offsetDate不是。和日期。格式也得到不同的结果,毫秒数NOT00结束。

format、toString、json文本的打印结果

LocalDateTime format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)@2015-08-15T11:40:10.1
LocalDateTime toString                                     @2015-08-15T11:40:10.100
LocalDateTime serialized json node text                    @2015-08-15T11:40:10.100
OffsetDateTime format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)@2015-08-15T11:40:10.1+08:00
OffsetDateTime toString                                      @2015-08-15T11:40:10.100+08:00
OffsetDateTime serialized json node text                     @2015-08-15T11:40:10.1+08:00
ZonedDateTime format(DateTimeFormatter.ISO_ZONED_DATE_TIME)@2015-08-15T11:40:10.1+08:00[Asia/Shanghai]
ZonedDateTime toString                                     @2015-08-15T11:40:10.100+08:00[Asia/Shanghai]
ZonedDateTime serialized json node text                    @2015-08-15T11:40:10.100+08:00[Asia/Shanghai]
  1. 似乎toString结果应该是Jackson序列化所需的结果,在上面的日志记录中,OffsetDateTime json节点微秒文本应该以00结束。
  2. 为什么format方法的结果省略了结尾00?

完整的示例代码可以从我的github.com找到。

angular-springmvc-sample-boot

ISODateTest

作为解决方法,我添加了自己的序列化器:

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModule(new JavaTimeModule());
    SimpleModule module = new SimpleModule();
    module.addSerializer(ZonedDateTime.class, new JsonSerializer<ZonedDateTime>() {
        @Override
        public void serialize(ZonedDateTime zonedDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
            jsonGenerator.writeString(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZZZ").format(zonedDateTime));
        }
    });
    objectMapper.registerModule(module);
    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    objectMapper.enable(SerializationFeature.INDENT_OUTPUT);

你的测试有两个问题:

  1. 你比较苹果和橙子,ObjectMapper序列化的结果和DateTimeFormatter格式化的结果。每个都有自己的默认值和配置选项,结果不同也就不足为奇了。
  2. 100_000_000实际上是1,根据ISO_LOCAL_TIME定义,DateTimeFormatter打印"纳秒1到9位数字"。根据需要输出任意数量的数字。"在您的情况下,只需要1位数字,这正是您在LocalDateTime的输出中得到的。

我不完全清楚你在这里想做什么,以及你写的测试的目的是什么。如果您希望格式化程序的精度达到3个数字的纳秒级,那么您必须使用自己的格式化程序。在代码中依赖toString格式是一个坏主意。

下面是我配置ObjectMapper的操作。

@Configuration
public class JacksonConfiguration {
  @Bean
  public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
    ObjectMapper objectMapper = builder.build();
    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    objectMapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false);
    return objectMapper;
  }
}

相关内容

  • 没有找到相关文章

最新更新