5

I've a LocalDateTime field with @JsonFormat

@JsonFormat(pattern = "yyyy-MM-dd'T'hh:mm:ss.SSS'Z'")
private LocalDateTime dateTime;

When Jackson try to parse a date like 2018-11-28T15:24:00.000Z a exception is throwed

com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of java.time.LocalDateTime: no String-argument constructor/factory method to deserialize from String value ('2018-11-28T15:24:00.000Z')

In my pom.xml i have:

  • Spring boot 1.5.7
  • jackson-datatype-jdk8
  • jackson-datatype-jsr310

My ObjectMapper Bean:

@Bean
public ObjectMapper postConstruct() {
    return this.builder
           .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
            .defaultUseWrapper(false)
            .build();
}

I also tried:

@JsonFormat(pattern = "yyyy-MM-dd'T'hh:mm:ss.SSS'Z'", timezone ="UTC")
private LocalDateTime dateTime;
cvdr
  • 939
  • 1
  • 11
  • 18
  • 2
    Your data **types are wrong**. Your formatting pattern is ignoring valuable info, the `Z` on the end means UTC. Delete the quote marks from around the `'Z'`. Then parse as a `Instant` or `OffsetDateTime` to represent a moment. A `LocalDateTime` by definition *cannot* represent a moment because it purposely lacks any concept of time zone or offset-from-UTC. – Basil Bourque Dec 17 '18 at 18:38
  • 1
    See: [*What's the difference between Instant and LocalDateTime?*](https://stackoverflow.com/q/32437550/642706) – Basil Bourque Dec 17 '18 at 20:26
  • I changed LocalDateTime to ZoneDateTime, remove the quote, but a JsonMappingException is throwed – cvdr Dec 17 '18 at 20:53
  • The `Z` means UTC, not a [full time zone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). So `ZonedDateTime` is not appropriate. `Instant` is the class you need: `Instant.parse( "2018-11-28T15:24:00.000Z" )`. Sorry, cannot help you with the Jackson aspect. Have you searched Stack Overflow? Date-time access with Jackson has been asked and answered many times already. – Basil Bourque Dec 17 '18 at 21:02
  • 1
    have you tried using `Date` instead of `LocalDateTime` @cvdr – Ryuzaki L Feb 22 '19 at 04:02
  • [`'Z'` is not the same as `Z`](https://stackoverflow.com/a/67953075/10819573). – Arvind Kumar Avinash Jul 18 '21 at 16:26

3 Answers3

8

I have faced similar issues. Reason for this issue is that mapper is not able to create a LocalDateTime instance from String object. Below will solve your problem.

@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonFormat(pattern = "yyyy-MM-dd'T'hh:mm:ss.SSS'Z'")
private LocalDateTime dateTime;

If you don't want to explicitly mention Serializer/Deseralizer, you will have to do either of below as per JackSon guide for release of DateTime Java 8 enhancements.

ObjectMapper mapper = new ObjectMapper()
   .registerModule(new ParameterNamesModule())
   .registerModule(new Jdk8Module())
   .registerModule(new JavaTimeModule());

OR

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

In SpringBoot, ObjectMapper instance is AutoWired & hence I don't know if we can explicitly do either of the solution. So for time being, dirty solution of explicitly mentioning Serializer/Deserializer is my best bet.

JackSon Java8 LocalDateTime enhancement ReadMe page is as below

https://github.com/FasterXML/jackson-modules-java8/blob/master/README.md

Surendra Raut
  • 370
  • 3
  • 9
  • The format should be "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", with uppcase "H". Otherwise the mapper will fail to parse the string as LocalDateTime, but LocalDate. Because "h" is 12-hrs presentation which need "AM/PM" notation, according to the answer: https://stackoverflow.com/a/52147072/4093741. – Da Tong Apr 22 '21 at 11:36
1

I also faced same issue and wrote custom serializer and de-serializer to solve the problem.

Below are the code snippets for the same:

import static java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME;
import java.io.IOException;
import java.time.LocalDateTime;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.node.TextNode;

public class JsonDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {

@Override
public LocalDateTime deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
        JsonProcessingException {
    ObjectCodec oc = jp.getCodec();
    TextNode node = (TextNode) oc.readTree(jp);
    String dateString = node.textValue();
    return LocalDateTime.parse(dateString, ISO_OFFSET_DATE_TIME);
    }
}


import static java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME;
import java.io.IOException;
import java.time.LocalDateTime;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

public class JsonDateTimeSerializer extends JsonSerializer<LocalDateTime> {
    @Override
    public void serialize(LocalDateTime date, JsonGenerator generator, SerializerProvider arg) throws IOException,
            JsonProcessingException {
        final String dateString = date.format(ISO_OFFSET_DATE_TIME);
        generator.writeString(dateString);
    }
}

**Using the above custom serializer and deserializer on the below request payload:**

    @JsonDeserialize(using = JsonDateTimeDeserializer.class)
    @JsonSerialize(using = JsonDateTimeSerializer.class)
    private LocalDateTime orderInitialized;
G.G.
  • 592
  • 5
  • 16
0

I also faced this issue when using OffsetDateTime. I simply added @JsonSerialize and @JsonDeserialize(wrote custom deserializer by extending JsonDeserializer<>) along with format. The issue got solved.

the_tech_maddy
  • 575
  • 2
  • 6
  • 21