简体   繁体   中英

Could not read JSON: Cannot construct instance of `java.time.ZonedDateTime` (no Creators, like default construct, exist)

I have a service that listens to a queue then maps it to a POJO. But I'm always getting this error even after setting the @Configuration of ObjectMapper

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        mapper.registerModule(new JavaTimeModule());

        return mapper;
    }

My POJO:

public class ResultDto {
    private ZonedDateTime dateSent;

    private ZonedDateTime dateDeliveryReceiptReceived;

    public ResultDto() {}
}

I get this error:

Caused by: org.springframework.messaging.converter.MessageConversionException: Could not read JSON: Cannot construct instance of `java.time.ZonedDateTime` (no Creators, like default construct, exist): no String-argument constructor/factory method to deserialize from String value ('2020-08-03T11:02:51.044+0000')

Thanks in advance!

Use @JsonFormat(pattern = 'specify pattern here')

ObjectMapper by default tries to create ZonedDateTime object with String in constructor and such thing does not exists. By adding this annotation you will allow it to parse it from String using given format.

From the error, it looks like it is looking for String -argument constructor. Try after adding the following constructors in ResultDto :

public ResultDto(ZonedDateTime dateSent, ZonedDateTime dateDeliveryReceiptReceived) {
    this.dateSent = dateSent;
    this.dateDeliveryReceiptReceived = dateDeliveryReceiptReceived;
}

public ResultDto(String dateSent, String dateDeliveryReceiptReceived) {
    this.dateSent = ZonedDateTime.parse(dateSent, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ"));
    this.dateDeliveryReceiptReceived = ZonedDateTime.parse(dateDeliveryReceiptReceived,
            DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ"));
}

Thanks for those who answered.

With the help of team mate, we discovered that the spring cloud has its own object mapper. And not the ObjectMapper directly. Since this DTO/POJO is to the message from a AWS SNS/SQS.

This should do:

@Bean
public MappingJackson2MessageConverter mappingJackson2MessageConverter(ObjectMapper objectMapper) {
    MappingJackson2MessageConverter jacksonMessageConverter = new MappingJackson2MessageConverter();
    jacksonMessageConverter.setObjectMapper(objectMapper);
    jacksonMessageConverter.setSerializedPayloadClass(String.class);
    jacksonMessageConverter.setStrictContentTypeMatch(true);
    return jacksonMessageConverter;
}

We face the same problem by using java 8, Springboot and AWS SQS. We create a custom deserializer which extends from InstantDeserializer for a ZonedDateTime. We apply the custom deserializer directly on the DTO which is associated to the SQS message.

import com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer;

import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class CustomZonedDateTimeDeserializer extends InstantDeserializer<ZonedDateTime> {
    public CustomZonedDateTimeDeserializer() {
        super(ZonedDateTime.class,
                DateTimeFormatter.ISO_ZONED_DATE_TIME,
                ZonedDateTime::from,
                a -> ZonedDateTime.ofInstant(Instant.ofEpochMilli(a.value), a.zoneId.getId().equals("UTC") ? ZoneOffset.UTC : a.zoneId),
                a -> ZonedDateTime.ofInstant(Instant.ofEpochSecond(a.integer, a.fraction), a.zoneId.getId().equals("UTC") ? ZoneOffset.UTC : a.zoneId),
                ZonedDateTime::withZoneSameInstant, false);
    }
}

In the DTO, we will have:

public class ResultDto {
    @JsonDeserialize(using = CustomZonedDateTimeDeserializer.class)
    private ZonedDateTime dateSent;

    @JsonDeserialize(using = CustomZonedDateTimeDeserializer.class)    
    private ZonedDateTime dateDeliveryReceiptReceived;

    public ResultDto() {}
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM