Force Milliseconds When Serializing Instant to ISO8601 using Jackson Force Milliseconds When Serializing Instant to ISO8601 using Jackson json json

Force Milliseconds When Serializing Instant to ISO8601 using Jackson


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


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


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.