How to convert Jackson deserialized ISO8601 formatted date-time into Java8 Instant

The Java 8 Instant class is used to record event time with relevance to UTC time zone.
You can pass ISO8601 formatted date-time or an date-time String value matching the pattern(“yyyy-MM-dd’T’HH:mm:ss.SSSZ”) or to de-serialize to an Instant value

In this tutorial, you will learn about Jackson’s way of De-serializing and Serializing ISO8601 formatted date-time into Java 8 Instant in detail.

Using LocalDateTime and Custom De-serializer

The Java LocalDateTIme can be used to represent ISO8601 formatted date-time.
Check this tutorial to convert a String to LocalDateTime, How to parse/format dates with Java 8 LocalDateTime


To Jackson’s way of De-serializing an ISO8601 formatted date-time into Instant,

  • Create a De-serializer class that extends JsonDeserializer<Instant>
  • Override the de-serialize () method and extract the input value.
  • Create a pattern("yyyy-MM-dd HH:mm:ss") using DateTimeFormatter
  • Use the LocalDateTime.parse(inputValue, formatter) method to convert the input value to the LocalDateTime value.
  • Convert the LocalDateTime value to Instant using .toInstant(ZoneOffset.UTC) method, specifying the time-zone to UTC. Instant value is also created based on the UTC time zone.

Use this approach when the input string does not contain complete values matching the Instant ISO-8601 pattern(yyyy-MM-dd’T’HH:mm:ss.SSSZ). When time-zone information is not present in the input string then De-serializer should set the time-zone value to get Instant value

Code

    //Employee.java
    import com.fasterxml.jackson.databind.annotation.JsonDeserialize;  
    import com.techmam.javatutorials.Java8InstantDeserializer;  
    import lombok.Data;  
    import lombok.NoArgsConstructor;  
    import java.time.Instant;  

    @Data  
    @NoArgsConstructor  
    public class Employee {  
        String name;  

        @JsonDeserialize(using = Java8InstantDeserializer.class)  
        Instant entryTime;  
        Instant currentTime;  
    }

    //Java8InstantDeserializer.java
    import com.fasterxml.jackson.core.JsonParser;  
    import com.fasterxml.jackson.databind.DeserializationContext;  
    import com.fasterxml.jackson.databind.JsonDeserializer;  
    import java.io.IOException;  
    import java.time.Instant;  
    import java.time.LocalDateTime;  
    import java.time.ZoneOffset;  
    import java.time.format.DateTimeFormatter;  

    public class Java8InstantDeserializer extends JsonDeserializer<Instant> {  
        @Override  
        public Instant deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {  
            String inputText = p.getValueAsString();  
            Instant instant = LocalDateTime.parse(inputText, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).toInstant(ZoneOffset.UTC);  
            return instant;  
        }  
    }

    //EmployeeController.Java
    import org.springframework.web.bind.annotation.PostMapping;  
    import org.springframework.web.bind.annotation.RequestBody;  
    import org.springframework.web.bind.annotation.RestController;  
    import java.time.Instant;  

    @RestController  
    public class EmployeeController {  
            @PostMapping("/employee")  
            public Employee createDetails(@RequestBody Employee employee) {  
                employee.setCurrentTime(Instant.now());  
                return employee;  
        }  
    }

    //Request Body
    {
        "name":"Pandey",
        "entryTime":"2023-01-01 23:33:34"
    }

Output

    {
        "name": "Pandey",
        "entryTime": "2023-01-01T23:33:34Z",
        "currentTime": "2023-02-26T11:00:54.478958700Z"
    }

In the above example, the ISO-8601 format date time value is parsed to an Instant value and returned in the response body.

Using @JsonFormat()

The @Jsonformat annotation can be used to Serialize a property by specifying a pattern.

Code

    //Employee.java
    @Data  
    @AllArgsConstructor  
    public class Employee {  
        String name;  
        @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ", shape = JsonFormat.Shape.STRING)  
        Instant entryTime;  
        Instant currentTime;  
    }

    //RequestBody
    {
        "name":"Pandey",
        "entryTime":"2023-01-01T23:33:34Z"
    }

Output

{
    "timestamp": "2023-02-25T21:11:05.677+0000",
    "status": 500,
    "error": "Internal Server Error",
    "trace": "org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Unsupported field: YearOfEra; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Unsupported field: YearOfEra...
}

When you try to serialize a formatted Instant value, it throws a JSON: Unsupported field: YearOfEra exception, as Instant does not support YearOfEra type while writing the response.

To resolve the above issue, the Instant value needs to be serialized to String, as shown below,

  • Create a new class for serializing Instant value which should extend JsonSerializer<Instant>.
  • The serializer class should override the serialize method and convert the Instant type value to String (InstantValue.toString()).
  • Invoke the JsonGenerator.writeString(string) method to write the string value in the response.
  • Use @JsonSerialize(using = Java8InstantSerializer.class) on the field level to serialize the Instant value.

Code

    //Employee.java
    public class Employee{  

        String name;  
        @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ", shape = JsonFormat.Shape.STRING)  
        @JsonSerialize(using = Java8InstantSerializer.class)  
        Instant entryTime;  
        Instant currentTime;  
    }

    //Java8InstantSerializer.java
    import com.fasterxml.jackson.core.JsonGenerator;  
    import com.fasterxml.jackson.databind.JsonSerializer;  
    import com.fasterxml.jackson.databind.SerializerProvider;  
    import java.io.IOException;  
    import java.time.Instant;  

    public class Java8InstantSerializer extends JsonSerializer<Instant> {  
        @Override  
        public void serialize(Instant value, JsonGenerator gen, SerializerProvider serializers) throws IOException {  
            gen.writeString(value.toString());  
        }  
    }

    //RequestBody
    {
        "name":"Pandey",
        "entryTime":"2023-01-01T23:33:34Z"
    }

Output

    {
        "name": "Pandey",
        "entryTime": "2023-01-01T23:33:34Z",
        "currentTime": "2023-02-25T21:17:21.430702900Z"
    }

Related Topics

Leave a Comment