How to set format of string for java.time.Instant using objectMapper?

73,462

Solution 1

For those looking to parse Java 8 timestamps. You need a recent version of jackson-datatype-jsr310 in your POM and have the following module registered:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

To test this code

@Test
void testSeliarization() throws IOException {
    String expectedJson = "{\"parseDate\":\"2018-12-04T18:47:38.927Z\"}";
    MyPojo pojo = new MyPojo(ZonedDateTime.parse("2018-12-04T18:47:38.927Z"));

    // serialization
    assertThat(objectMapper.writeValueAsString(pojo)).isEqualTo(expectedJson);

    // deserialization
    assertThat(objectMapper.readValue(expectedJson, MyPojo.class)).isEqualTo(pojo);
}

Solution 2

Here's some Kotlin code of formatting Instant, so it does not contain milliseconds, you can use custom date formatters

ObjectMapper().apply {
        val javaTimeModule = JavaTimeModule()
        javaTimeModule.addSerializer(Instant::class.java, Iso8601WithoutMillisInstantSerializer())
        registerModule(javaTimeModule)
        disable(WRITE_DATES_AS_TIMESTAMPS)
    }

private class Iso8601WithoutMillisInstantSerializer
        : InstantSerializer(InstantSerializer.INSTANCE, false, DateTimeFormatterBuilder().appendInstant(0).toFormatter())

Solution 3

You need to add below dependency

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.6.5</version>
</dependency>

And then register the modules as below :

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules();

Solution 4

In my case it was enough to register the JavaTimeModule:

  ObjectMapper objectMapper = new ObjectMapper();
  JavaTimeModule module = new JavaTimeModule();
  objectMapper.registerModule(module);

  messageObject = objectMapper.writeValueAsString(event);

In the event Object I have a field of type Instant.

In the deserialization you also need to register the java time module:

ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());

Event event = objectMapper.readValue(record.value(), Event.class);

Solution 5

If using Spring, and spring-web is on the classpath, you can create an ObjectMapper using the Jackson2ObjectMapperBuilder. It registers the following commonly used modules within the method registerWellKnownModulesIfAvailable.

com.fasterxml.jackson.datatype.jdk8.Jdk8Module
com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
com.fasterxml.jackson.datatype.joda.JodaModule
com.fasterxml.jackson.module.kotlin.KotlinModule

Some of these modules have been merged into Jackson 3; see here.

Share:
73,462
Uladzislau Kaminski
Author by

Uladzislau Kaminski

Chief Information Officer at Oyper Inc. Experience with Java since 2014 year.

Updated on November 12, 2020

Comments

  • Uladzislau Kaminski
    Uladzislau Kaminski over 3 years

    I have an entity with java.time.Instant for created data field:

    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    @EqualsAndHashCode
    public class Item {
        private String id;
        private String url;
        private Instant createdDate;
    }
    

    I am using com.fasterxml.jackson.databind.ObjectMapper to save item to Elasticsearch as JSON:

    bulkRequestBody.append(objectMapper.writeValueAsString(item));
    

    ObjectMapper serializes this field as an object:

    "createdDate": {
        "epochSecond": 1502643595,
        "nano": 466000000
    }
    

    I was trying the annotation @JsonFormat(shape = JsonFormat.Shape.STRING) but it doesn't work for me.

    My question is how I could serialize this field as 2010-05-30 22:15:52 string?