JSON Java 8 Localdatetime Format in Spring Boot

JSON Java 8 LocalDateTime format in Spring Boot

update: Spring Boot 2.x doesn't require this configuration anymore. I've written a more up to date answer here.


(This is the way of doing it before Spring Boot 2.x, it might be useful for people working on an older version of Spring Boot)

I finally found here how to do it. To fix it, I needed another dependency:

compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.4.0")

By including this dependency, Spring will automatically register a converter for it, as described here. After that, you need to add the following to application.properties:

spring.jackson.serialization.write_dates_as_timestamps=false

This will ensure that a correct converter is used, and dates will be printed in the format of 2016-03-16T13:56:39.492

Annotations are only needed in case you want to change the date format.

LocalDateTime parsing with jackson

Thank you to @mohammedkhan for the guide!

In this answer:
JSON Java 8 LocalDateTime format in Spring Boot

There's already a setting in spring-boot there's no need to @Autowire the ObjectMapper

dd this annotation for the Json Deserializer

@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateOccurred;

Thank you!

Deserialize Java 8 LocalDateTime with JacksonMapper

The date time you're passing is not an ISO local date time format.

Change to

@Column(name = "start_date")
@DateTimeFormat(iso = DateTimeFormatter.ISO_LOCAL_DATE_TIME)
@JsonFormat(pattern = "YYYY-MM-dd HH:mm")
private LocalDateTime startDate;

and pass the date string in the format '2011-12-03T10:15:30'.

But if you still want to pass your custom format, you just have to specify the right formatter.

Change to

@Column(name = "start_date")
@DateTimeFormat(iso = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
@JsonFormat(pattern = "YYYY-MM-dd HH:mm")
private LocalDateTime startDate;

I think your problem is the @DateTimeFormat has no effect at all. As the Jackson is doing the deserialization and it doesn't know anything about spring annotation, and I don't see spring scanning this annotation in the deserialization context.

Alternatively, you can try setting the formatter while registering the Java time module.

LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);

Here is the test case with the deseralizer which works fine. Maybe try to get rid of that DateTimeFormat annotation altogether.

@RunWith(JUnit4.class)
public class JacksonLocalDateTimeTest {

private ObjectMapper objectMapper;

@Before
public void init() {
JavaTimeModule module = new JavaTimeModule();
LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);
objectMapper = Jackson2ObjectMapperBuilder.json()
.modules(module)
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.build();
}

@Test
public void test() throws IOException {
final String json = "{ \"date\": \"2016-11-08 12:00\" }";
final JsonType instance = objectMapper.readValue(json, JsonType.class);

assertEquals(LocalDateTime.parse("2016-11-08 12:00",DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm") ), instance.getDate());
}
}

class JsonType {
private LocalDateTime date;

public LocalDateTime getDate() {
return date;
}

public void setDate(LocalDateTime date) {
this.date = date;
}
}

Spring boot: JSON deserialize date and time with time zone to LocalDateTime

There are two problems with your code:

1. Use of wrong type

Cannot deserialize value of type java.time.LocalDateTime from String
"2019-10-21T13:00:00+02:00": Failed to deserialize
java.time.LocalDateTime: (java.time.format.DateTimeParseException)
Text '2019-10-21T13:00:00+02:00' could not be parsed, unparsed text
found at index 19

If you analyze the error message, you will find that it is clearly telling you that there is some problem at index 19.

2019-10-21T13:00:00+02:00
// index 19 ----> ^

And, the problem is that LocalDateTime does not support timezone. Given below is an overview of java.time types and you can see that the type which matches with your date-time string is OffsetDateTime because it has a zone offset of +02:00 hours.

Sample Image

Change your declaration as follows:

private OffsetDateTime startTime;

2. Use of wrong format

You need to use XXX for the offset part i.e. your format should be uuuu-MM-dd'T'HH:m:ssXXX. If you want to stick to Z, you need to use ZZZZZ. Check the documentation page of DateTimeFormatter for more details.

Demo:

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
public static void main(String[] args) {
String strDateTime = "2019-10-21T13:00:00+02:00";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:m:ssXXX");
OffsetDateTime odt = OffsetDateTime.parse(strDateTime, dtf);
System.out.println(odt);
}
}

Output:

2019-10-21T13:00+02:00

Learn more about the modern date-time API from Trail: Date Time.

Also related, RFC3339 - Date and Time on the Internet: Timestamps

This document defines a date and time format for use in Internet

protocols that is a profile of the ISO 8601 standard for

representation of dates and times using the Gregorian calendar.

LocalDateTime is representing in array format

The culprit was @EnableWebMVC. One of my cors class was having @EnableWebMVC annotation. This was disabling the spring boot auto configuration and also overriding the mapper confiiguration. This won't let you to override the configuration of object mapper. By removing @EnableMVC annotation, this is working fine now. In SpringBoot2, we don't need to do any configuration explicitly related to date serialization, it will automatically parse the java 8 dates in "yyyy-mm-dd" format.

Json string from LocalDateTime(java 8) in Spring MVC

A similar question is answered here. You may have to add @JsonSerialize(using = LocalDateTimeSerializer.class) to your field.

You can also create a custom serializer like below:

public class CustomLocalDateTimeSerializer extends JsonSerializer<LocalDateTime>{

@Override
public void serialize(LocalDateTime dateTime, JsonGenerator generator, SerializerProvider sp)
throws IOException, JsonProcessingException {
String formattedDateTime = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
generator.writeString( formattedDateTime);
}

}

and use that custom serializer in your LocalDateTime field:

@JsonSerialize(using = CustomLocalDateTimeSerializer.class)
private LocalDateTime w_date;

How to parse LocalDate with Jackson

Since you set values through contructor, not setters, you should put @JsonFormat(...) on constructor parameters, not fields. This should fix it:

public class LeaveApplUx {

@JsonIgnore
private final String employeeCode;

private final LocalDate startDate;

@JsonIgnore
private final LocalDate rejoinDate;

public LeaveApplUx(@JsonProperty("employeeCode") String employeeCode,
@JsonProperty("startDate") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") LocalDate startDate,
@JsonProperty("rejoinDate") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") LocalDate rejoinDate) {
this.employeeCode = employeeCode;
this.startDate = startDate;
this.rejoinDate = rejoinDate;
}

//getters
}

LocalDateTime not displaying as timestamps (ie as a long) java 8 spring boot 2.2.0

Thanks to @deHaar who gave me some hints I've found how to proceed.

I created a custom serializer :

public class LocalDateTimeSerialize extends StdSerializer<LocalDateTime> {

public LocalDateTimeSerialize(Class<LocalDateTime> t) {
super(t);
}

@Override
public void serialize(LocalDateTime localDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
Long l = localDateTime.toInstant(OffsetDateTime.now().getOffset())
.toEpochMilli();
jsonGenerator.writeString(l.toString());
}
}

I change my extendMessageConverters to use this custom serializer in my objectMapper :

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule()
.addSerializer(LocalDateTime.class, new LocalDateTimeSerialize(LocalDateTime.class)));


Related Topics



Leave a reply



Submit