skip to Main Content

I am trying to use Spring to deserialize incoming JSON objects. I have the following class:

public class ContentRequestMessage {
    
    private String type;

    private String messageId;

    private String topicArn;
    
    /**
     * Message contents:
     * 
     * "Message" : "{"location": "/interactments/d2734-9304cceb7c3a", "status": "draft_created"}"
     */
    private Map<String, Object> message;

    private Date timestamp;

    private String signatureVersion;

    private String signature;

    private String signingCertURL;

    private String unsubscribeURL;
    
    private Map<String, Object> messageAttributes;
    
    //constructors, getters & setters
}

I am trying to feed the following JSON request:

{
  "type" : "Notification",
  "messageId" : "b2b769284",
  "topicArn" : "arn:aws:sn",
  "message" : "{"location": "/interacments/d275d0-893ceb7c3a", "status": "draft_created"}",
  "timestamp" : "2023-01-03T11:17:29.537Z",
  "signatureVersion" : "1",
  "signature" : "1Jag1w==",
  "signingCertURL" : "https://2625d385.pem",
  "unsubscribeURL" : "httbscri2b1f502953",
  "messageAttributes" : {
    "scope" : {"Type":"String","Value":"nas_consumer"}
  }
}

Into my controller:

@RestController
public class TestController {
    
    @PostMapping
    public void postRequest(@RequestBody ContentRequestMessage contentRequestMessage) {
        
        System.out.println(contentRequestMessage);
        
    }
}

But I am encountering the following error:

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `java.util.LinkedHashMap` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"location": "/interactments/d2734-9304cceb7c3a", "status": "draft_created"}')

Other threads discuss using an ObjectMapper and Jackson, but I want to rely on Spring to deserialize this object for me. What is going wrong here?

2

Answers


  1. Your message is not a map, but a simple String.

    The content of messageAttributes.scope itself is a map again, and not an Object.

    Try this:

    public class ContentRequestMessage {
      private String type;
      private String messageId;
      private String topicArn;
      private String message;
      private Date timestamp;
      private String signatureVersion;
      private String signature;
      private String signingCertURL;
      private String unsubscribeURL;
      private Map<String, Map<String, String>> messageAttributes;
    
      // rest of implementation
    }
    
    Login or Signup to reply.
  2. im a newcomer to StackOverflow

    From your question, it seems to have a problem of serialize.

    I guess you want to convert to this type:

    message.get(location); //  "/interacments/d275d0-893ceb7c3a"
    message.get(status);  //   "draft_created"
    

    But on your JSON request:

    {
    "type" : "Notification",
    "messageId" : "b2b769284",
    "topicArn" : "arn:aws:sn",
    "message" : "
                {"location": "/interacments/d275d0-893ceb7c3a", 
                   "status": "draft_created"
                }",
    "timestamp" : "2023-01-03T11:17:29.537Z",
    "signatureVersion" : "1",
    "signature" : "1Jag1w==",
    "signingCertURL" : "https://2625d385.pem",
    "unsubscribeURL" : "httbscri2b1f502953",
    "messageAttributes" : { 
          "scope" : {"Type":"String","Value":"nas_consumer"}
        }
    }
    

    The field name messageAttributes is same of message, so why the messageAttributes not throw exception?

    From the JSON perspective , the field message provides the String, messageAttributes provides the Map.

    So this real problem is spring cannot deserialize String to Map.

    {
     "message" : {
               "location": "interacments/d275d0-893ceb7c3a", 
               "status": "draft_created"
              }
     }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search