Spring boot SQS消息中的时间戳可以';不能在弹簧靴中转换

Spring boot SQS消息中的时间戳可以';不能在弹簧靴中转换,spring-boot,jackson,amazon-sqs,date,Spring Boot,Jackson,Amazon Sqs,Date,我创建了一个DTO来将来自AWS SES的消息通过SNS映射到SQS,但是时间戳转换器在spring boot创建的objectMapper中无法正常工作。我试图将时间戳映射为(ZonedDateTime/LocalDateTime/Instant),但总是出现错误 我使用了这些版本 spring启动版本是2.2.5 spring云版本是Hoxton.SR3 我明确指定Jackson版本为2.9 这是留言 { "notificationType": "Bounce", "bounce":

我创建了一个DTO来将来自AWS SES的消息通过SNS映射到SQS,但是时间戳转换器在spring boot创建的
objectMapper
中无法正常工作。我试图将时间戳映射为(
ZonedDateTime
/
LocalDateTime
/
Instant
),但总是出现错误

我使用了这些版本 spring启动版本是2.2.5 spring云版本是Hoxton.SR3 我明确指定Jackson版本为2.9

这是留言

{
  "notificationType": "Bounce",
  "bounce": {
    "bounceType": "Permanent",
    "bounceSubType": "Suppressed",
    "bouncedRecipients": [
      {
        "emailAddress": "blacklist@simulator.amazonses.com",
        "action": "failed",
        "status": "5.1.1",
        "diagnosticCode": "Amazon SES has suppressed sending to this address because it has a recent history of bouncing as an invalid address. For more information about how to remove an address from the suppression list, see the Amazon SES Developer Guide: http://docs.aws.amazon.com/ses/latest/DeveloperGuide/remove-from-suppressionlist.html "
      }
    ],
    "timestamp": "2020-03-20T21:00:42.217Z",
    "feedbackId": "01070170f9bf8131-9cbe20b1-7997-4d33-8e02-7e828eb01edc-000000",
    "reportingMTA": "dns; amazonses.com"
  },
  "mail": {
    "timestamp": "2020-03-20T21:00:42.217Z",
    "source": "tester@####.com",
    "sourceArn": "arn:aws:ses:eu-central-1:425905684163:identity/####",
    "sourceIp": "54.239.6.46",
    "sendingAccountId": "425905684163",
    "messageId": "01070170f9bf8091-79e59712-3c2d-424c-9eba-3e221ef336ff-000000",
    "destination": [
      "blacklist@simulator.amazonses.com"
    ],
    "headersTruncated": false,
    "headers": [
      {
        "name": "From",
        "value": "tester@####.com"
      },
      {
        "name": "To",
        "value": "blacklist@simulator.amazonses.com"
      },
      {
        "name": "Subject",
        "value": "lkasnlkaslknaslkn"
      },
      {
        "name": "MIME-Version",
        "value": "1.0"
      },
      {
        "name": "Content-Type",
        "value": "text/plain; charset=UTF-8"
      },
      {
        "name": "Content-Transfer-Encoding",
        "value": "7bit"
      }
    ],
    "commonHeaders": {
      "from": [
        "*****"
      ],
      "to": [
        "blacklist@simulator.amazonses.com"
      ],
      "subject": "lkasnlkaslknaslkn"
    }
  }
}
反弹对象的贴图为

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Bounce {
    private BounceType bounceType;
    private BounceSubType bounceSubType;
    private List<Recipient> bouncedRecipients;
    private ZonedDateTime timestamp;
    private String feedbackId;
    private String remoteMtaIp;
    private String reportingMTA;

    public static enum BounceType {
        Permanent, Transient
    }

    public static enum BounceSubType {
        General, Suppressed
    }

}
@数据
@AllArgsConstructor
@诺尔格构装师
@建筑商
@JsonInclude(JsonInclude.Include.NON_EMPTY)
公务舱弹跳{
私有BounceType BounceType;
私有弹跳子类型弹跳子类型;
私人名单被反弹的候选人;
私有分区日期时间戳;
私有字符串反馈ID;
私有字符串remoteMtaIp;
私有字符串报告MTA;
公共静态枚举BounceType{
永久的,暂时的
}
公共静态枚举反弹子类型{
将军,镇压
}
}

jackson-modules-java8可以做到这一点。这对我很有用:

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

    String message = "{ \"timestamp\": \"2020-03-20T21:00:42.217Z\" }";

    Dto obj = mapper.readValue(message, Dto.class);

    System.out.println(obj.getTimestamp());
输出是(正如您所预期的):

请注意,我正在映射器上显式注册Jackson java.time模块。如果还要使用映射器进行序列化,则还需要:

    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
为了完整的示例,我使用的
Dto
类非常简单,只是一个包含getter和setter的字段:

public class Dto {

    private Instant timestamp;

    public Instant getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(Instant timestamp) {
        this.timestamp = timestamp;
    }

}
我没有尝试使用类型为
ZonedDateTime
OffsetDateTime
的字段,但如果它们不起作用,我会非常惊讶。在任何情况下,如果你的时间戳总是在UTC中,并且总是有UTC的尾随<代码> Z <代码>,那么我会考虑<代码>即时< /COD>在java中它是最正确的类型。 链接

jackson-modules-java8可以做到这一点。这对我很有用:

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

    String message = "{ \"timestamp\": \"2020-03-20T21:00:42.217Z\" }";

    Dto obj = mapper.readValue(message, Dto.class);

    System.out.println(obj.getTimestamp());
输出是(正如您所预期的):

请注意,我正在映射器上显式注册Jackson java.time模块。如果还要使用映射器进行序列化,则还需要:

    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
为了完整的示例,我使用的
Dto
类非常简单,只是一个包含getter和setter的字段:

public class Dto {

    private Instant timestamp;

    public Instant getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(Instant timestamp) {
        this.timestamp = timestamp;
    }

}
我没有尝试使用类型为
ZonedDateTime
OffsetDateTime
的字段,但如果它们不起作用,我会非常惊讶。在任何情况下,如果你的时间戳总是在UTC中,并且总是有UTC的尾随<代码> Z <代码>,那么我会考虑<代码>即时< /COD>在java中它是最正确的类型。 链接

我能做到。@OleV.V。spring 2及更高版本已经添加了此模块!我通过添加我自己的反序列化程序解决了这个问题。请向我展示您的
MappingJackson2MessageConverter
QueueMessagingTemplate
的bean配置,您每次添加LocalDateTime字段时都添加了自己的反序列化程序吗?奥列夫:我能做到。spring 2及更高版本已经添加了此模块!我通过添加我自己的反序列化程序解决了这个问题。请向我展示您的
MappingJackson2MessageConverter
QueueMessagingTemplate
的bean配置,您每次添加LocalDateTime字段时都添加了您自己的反序列化程序?您所做的是正确的,但我正在spring boot下工作,其中包括开箱即用的配置当消息被反序列化时,似乎出现了一个问题。我想为spring boot和spring Cloud找到一些解决方案。我在工作中使用了spring boot。使用SpringBoot与RESTfulWeb服务交换JSON,并使用上面类似的代码将JSON转换为我自己的对象类型。很抱歉,我没有使用Spring-cloud的经验。您所做的是正确的,但我在Spring boot下工作,其中包括开箱即用配置,当消息被反序列化时,似乎出现了问题。我希望为Spring boot和Spring cloud提供一些解决方案。我在工作中使用了Spring boot。使用SpringBoot与RESTfulWeb服务交换JSON,并使用上面类似的代码将JSON转换为我自己的对象类型。很抱歉,我没有使用Spring cloud的经验。