问题
I have some questions related to JSON serialization using Jackson in a project where I use Spring Boot 2.0.0.M6
, Spring Framework 5.0.1.RELEASE
and Jackson 2.9.2
.
I have configured the following Jackson-related settings in application.properties
:
spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false
Serialization works mostly as I need. Nevertheless, I have noticed that Jackson seems to cut-off milliseconds if they are 000
.
Test 1: Serialize Instant with milliseconds set to 000
:
- Initialize Instant field using
Instant.parse("2017-09-14T04:28:48.000Z")
- Serialize it using Jackson
- Output will be
"2017-09-14T04:28:48Z"
Test 2: Serialize Instant with milliseconds set to some non-000
value:
- Initialize Instant field using
Instant.parse("2017-09-14T04:28:48.100Z")
- Serialize it using Jackson
- Output will be
"2017-09-14T04:28:48.100Z"
Questions:
- Is that behavior by design?
- Is there anything I can do to force serialization of
000
?
回答1:
There appears to be a Jackson issue open for this here*. That link contains two workarounds
Workaround 1
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);
Workaround 2
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(ZonedDateTime.class,
new ZonedDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX")));
ObjectMapper mapper = new ObjectMapper().registerModule(javaTimeModule);
*Link is dead because they deprecated FasterXML/jackson-datatype-jsr310 and moved it to jackson-modules-java8. See https://github.com/FasterXML/jackson-modules-java8/issues/76
回答2:
I solve using this aproach:
ObjectMapper objectMapper = new ObjectMapper();
JavaTimeModule module = new JavaTimeModule();
module.addSerializer(Instant.class, new InstantSerializerWithMilliSecondPrecision());
objectMapper.registerModule(module);
And for InstantSerializerWithMilliSecondPrecision i used this:
public class InstantSerializerWithMilliSecondPrecision extends InstantSerializer {
public InstantSerializerWithMilliSecondPrecision() {
super(InstantSerializer.INSTANCE, false, new DateTimeFormatterBuilder().appendInstant(3).toFormatter());
}
}
Now the Instant serialization always includes milliseconds. Example: 2019-09-27T02:59:59.000Z
回答3:
None of two workarounds mentioned by Sean Carroll works me. I end up with writing my own serializer for Instant.
final ObjectMapper mapper = new ObjectMapper();
final JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(Instant.class, new KeepMillisecondInstantSerializer());
mapper.registerModule(javaTimeModule);
public class KeepMillisecondInstantSerializer extends JsonSerializer<Instant> {
private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX")
.withZone(ZoneId.of("UTC"));
@Override
public void serialize(final Instant instant, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider) throws IOException {
final String serializedInstant = dateTimeFormatter.format(instant);
jsonGenerator.writeString(serializedInstant);
}
}
I guess Jackson use Instant.toString() method to serialize Instant objects by default. I also find some discussions about Instant.toString() method on StackOverflow.
来源:https://stackoverflow.com/questions/47502158/force-milliseconds-when-serializing-instant-to-iso8601-using-jackson