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 theInstant
type value toString
(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"
}