Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force Milliseconds When Serializing Instant to ISO8601 using Jackson

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?
like image 213
André Gasser Avatar asked Nov 26 '17 23:11

André Gasser


People also ask

How do you tell Jackson to ignore a field during serialization?

If there are fields in Java objects that do not wish to be serialized, we can use the @JsonIgnore annotation in the Jackson library. The @JsonIgnore can be used at the field level, for ignoring fields during the serialization and deserialization.

What is serialization in Jackson?

ObjectMapper is Jackson's serialization mapper. It allows us to serialize our map, and write it out as a pretty-printed JSON String using the toString() method in String: { "key" : "value" }

Does Jackson use serializable?

Note that Jackson does not use java. io. Serializable for anything: there is no real value for adding that. It gets ignored.

Can Jackson serialize interface?

Jackson can serialize and deserialize polymorphic data structures very easily. The CarTransporter can itself carry another CarTransporter as a vehicle: that's where the tree structure is! Now, you know how to configure Jackson to serialize and deserialize objects being represented by their interface.


2 Answers

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

like image 90
Gustavo Avatar answered Sep 25 '22 17:09

Gustavo


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

like image 20
Sean Carroll Avatar answered Sep 23 '22 17:09

Sean Carroll