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

huangapple go评论56阅读模式
英文:

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

问题

我有一个监听队列并将其映射到POJO的服务。但是,即使设置了ObjectMapper的@Configuration,我仍然不断收到以下错误:

	@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;
	}

我的POJO:

public class ResultDto {
	private ZonedDateTime dateSent;

	private ZonedDateTime dateDeliveryReceiptReceived;

	public ResultDto() {}
}

我收到以下错误:

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')

提前致谢!

英文:

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!

答案1

得分: 1

使用@JsonFormat(pattern = '在此指定格式'),ObjectMapper 默认尝试在构造函数中创建 ZonedDateTime 对象,但这种对象不存在。通过添加此注解,您将允许它使用指定的格式从字符串中解析它。

英文:

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.

答案2

得分: 1

From the error, it looks like it is looking for a 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"));
}
英文:

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"));
}

答案3

得分: 1

感谢那些回答的人。

在队友的帮助下,我们发现Spring Cloud有自己的对象映射器,而不是直接使用ObjectMapper。由于这个DTO/POJO是用于处理来自AWS SNS/SQS的消息,应该这样做:

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

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;
}

答案4

得分: 0

我们在使用Java 8、Spring Boot和AWS SQS时遇到了相同的问题。我们创建了一个自定义的反序列化器,它扩展自InstantDeserializer以处理ZonedDateTime。我们直接将自定义反序列化器应用于与SQS消息关联的DTO。

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);
    }
}

在DTO中,我们会有:

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

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

    public ResultDto() {}
}
英文:

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&lt;ZonedDateTime&gt; {
    public CustomZonedDateTimeDeserializer() {
        super(ZonedDateTime.class,
                DateTimeFormatter.ISO_ZONED_DATE_TIME,
                ZonedDateTime::from,
                a -&gt; ZonedDateTime.ofInstant(Instant.ofEpochMilli(a.value), a.zoneId.getId().equals(&quot;UTC&quot;) ? ZoneOffset.UTC : a.zoneId),
                a -&gt; ZonedDateTime.ofInstant(Instant.ofEpochSecond(a.integer, a.fraction), a.zoneId.getId().equals(&quot;UTC&quot;) ? 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() {}
}

huangapple
  • 本文由 发表于 2020年8月3日 22:45:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/63231624.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定