本文介绍了杰克逊反序列化SNS消息错误MismatchedInputException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一种通过SNS HTTP请求处理来自Amazon Simple Email Service的回调的功能.我想将Amazon提供的消息解析为本地对象结构.问题是SNS将JSON消息包装到String中,而Jackson无法对其进行解析.我遇到错误:

I'm coding a functionality of handling callbacks from Amazon Simple Email Service via SNS HTTP requests. I would like to parse message provided by Amazon to local object structure. Problem is that SNS is wrapping JSON message into String and it could not be parsed by Jackson. I'm getting an error:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `xxx.email.domain.aws.ses.Notification` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"notificationType":"Delivery","mail":{"timestamp":"2019-10-02T14:43:14.570Z" ... next values of the message ... }}')

来自SNS的整个消息如下:

Entire message from SNS looks like this one:

 {
  "Type" : "Notification",
  "MessageId" : "4944xxxx-711d-57d4-91b8-8215cxxxxx",
  "TopicArn" : "arn:aws:sns:eu-west-1:...",
  "Message" : "{\"notificationType\":\"Delivery\",\"mail\":{\"timestamp\":\"2019-10-02T14:43:14.570Z\", ... next values of the message ... },\"delivery\":{\"timestamp\":\"2019-10-02T14:43:16.030Z\", ... next values of the message ... }}",
  "Timestamp" : "2019-10-02T14:43:16.062Z",
  "SignatureVersion" : "1",
  "Signature" : "signature base64",
  "SigningCertURL" : "cert url",
  "UnsubscribeURL" : "unsubscribe url"
}

我的实际本地结构如下:

My actual local structure looks like this:

@Data
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
public class MessageWrapper {
    private String type;
    private String messageId;
    private String topicArn;
    private Notification message;
    private Date timestamp;
    private String signatureVersion;
    private String signature;
    private String signingCertURL;
    private String unsubscribeURL;
}

@Data
public class Notification {
    private String notificationType;
    private Mail mail;
}

@Data
public class Mail {
    private String messageId;
    private String source;
    private String sourceArn;
    private String sourceIp;
    private String sendingAccountId;
    private String[] destination;
}

我正在寻找一种方法来告诉杰克逊Message应该从字符串中提取并作为普通JSON处理.

I'm looking for some way to tell Jackson that Message should be extracted from a String and treated as a normal JSON.

修改

反序列化

private MessageWrapper deserializeMessage(String message) throws IOException {
    return new ObjectMapper().readValue(message, MessageWrapper.class);
}

推荐答案

我想解决此问题,您需要为MessageWrapper类中的Notification字段以及在MessageWrapper类中的Mail字段使用一个自定义反序列化器. Notification类如下:

I think to solve this you'll need a custom deserializer for Notification field in MessageWrapper class as well as one for the Mail field in the Notification class the like the following:

public class NotificationDeserializer extends JsonDeserializer<Notification> {
    @Override
    public Notification deserialize(JsonParser p, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        String text = p.getText();

        return new ObjectMapper().readValue(text, Notification.class);
    }
}

public class MailDeserializer extends JsonDeserializer<Mail> {
    @Override
    public Mail deserialize(JsonParser p, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        String text = p.getText();

        return new ObjectMapper().readValue(text, Mail.class);
    }
}

在类上带有一些注释,如下所示:

With some annotations on your classes like the following:

@Data
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
public class MessageWrapper {
    private String type;
    private String messageId;
    private String topicArn;
    @JsonDeserialize(using = NotificationDeserializer.class)
    private Notification message;
    private Date timestamp;
    private String signatureVersion;
    private String signature;
    private String signingCertURL;
    private String unsubscribeURL;
}

@Data
public class Notification {
    private String notificationType;
    @JsonDeserialize(using = MailDeserializer.class)
    private Mail mail;
}

@Data
public class Mail {
    private String messageId;
    private String source;
    private String sourceArn;
    private String sourceIp;
    private String sendingAccountId;
    private String[] destination;
}

编辑1

实际上不需要MailDeserializer.单独使用NotificationDeserializer即可解决问题.

The MailDeserializer isn't actually needed. The NotificationDeserializer alone takes care of the issue.

编辑2

必须在自定义解串器中使用新的ObjectMapper.

Using a new ObjectMapper in the custom deserializer is a must.

这篇关于杰克逊反序列化SNS消息错误MismatchedInputException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-31 05:08