Home > Blockchain >  Spring doesn't correctly serialize JSON to Java Map
Spring doesn't correctly serialize JSON to Java Map

Time:03-22

I have a form that contains multiple radio inputs and one textarea input that I send using axios from a ReactJs client. The request looks like this:

  axios.post("/wellbeing/"   params.wellbeingSurveyType, { formAnswersJson: formAnswers })
    .then(res => {
      // logic
    })
    .catch(err => {
      // logic
    })

The 'formAnswers' object looks like this: enter image description here

I then receive the request from a Spring controller that looks like the following:

    @PostMapping("{wellbeingSurveyType}")
    public WellbeingSurveySubmission submitSurvey(
            @PathVariable WellbeingSurveyType wellbeingSurveyType,
            @RequestBody String formAnswersJson) throws JsonProcessingException {
        var result = new ObjectMapper().readValue(formAnswersJson, HashMap.class);
        return new WellbeingSurveySubmission(); //ignore this
    }

When I call the 'toString()' method on the result object it seems to correctly print out the map values: enter image description here

But when I try to actually operate on the object (which is parsed as a LinkedHashMap) I cannot access the keys or values: enter image description here

When I try to open up the object using the debugging tool it seems to store a reference to itself as a value: enter image description here

The result I want is simply a Map<String, String> that represents the JSON but I am unsure why this behavior is happening.

Any help or tips on how to do this in a better way would be greatly appreciated, thank you.

CodePudding user response:

If you pass a JavaScript object as the 2nd parameter to the axios.post() function, Axios will automatically serialize the object to JSON for you.

So, with this line of code :

axios.post("/wellbeing/"   params.wellbeingSurveyType, { formAnswersJson: formAnswers })

You are basically sending object with key fromAnswersJson and value fromAnswers to your rest controller and Spring will deserilize it like a Map with key fromAnswersJson and value fromAnswers

To get what you want just send your request like this :

axios.post("/wellbeing/"   params.wellbeingSurveyType, formAnswers )

CodePudding user response:

Alright the best way I found to make this work was to deconstruct the JSON object in the axios post request like so:

axios.post("/wellbeing/"   params.wellbeingSurveyType, { ...formAnswers })
        .then(res => {
          // logic
        })
        .catch(err => {
          // logic
        })

Works better as if I just pass the formAnswers object it unnecessarily wraps the object i.e. A hashmap that contains a single key-value pair 'formAnswers'.

Although as The Frozen One mentioned, it would be better to define a dedicated form object and take it as a param in the spring controller.

CodePudding user response:

It Seems like the conversion from String to Map in java does not go smoothly from what I see in your printscreen.

Personally, I do not work like that when I handle requests. I create a dto object and give that in the controller as input. The fact that you have variables that the name is a number make that a bit more complicated since java cannot accept that as a valid variable name, but probably (did not test it) can be overcome by using @JsonProperty. So my solution would be the following

@Getter
@Setter
public class MyRequestDto {
    @JsonProperty("user-comment")
    private String userComment;
    @JsonProperty("0")
    private String zero;
    @JsonProperty("1")
    private String one;
    @JsonProperty("2")
    private String two;
...

}

I added lombok getters and setters ofcourse you can add your own if you don't use lombok.

Then replace the input in your controller

@PostMapping("{wellbeingSurveyType}")
public WellbeingSurveySubmission submitSurvey(
        @PathVariable WellbeingSurveyType wellbeingSurveyType,
        @RequestBody MyRequestDto request) throws JsonProcessingException {
        request.getUserComment()
        return new WellbeingSurveySubmission(); //ignore this
    }
  • Related