1

From what I have searched and found this very well may not be possible but any help would be appreciated.

I have a spring controller that accepts a DTO that I have created and one of the attributes is a Map. On my html page I am trying to bundle a map from the page into the JSON but the only way I have found to do this is to convert the map into an array. This causes the deserialization to fail because of incompatible types.

E.G.

Controller:

@PostMapping("/mapping")
public ResponseEntity addThing(@Validated @RequestBody Dto dto, BindingResult result){
    //Do some stuff
}

Dto:

public class Dto {
     ...
     private Map<Integer, String> map;
     ...
}

Javascript:

...
var map = new Map();
$("#mapBody tr").map(function () {
     var value = $(this).find( "input[name=value]").val();
     var index = $(this).find("input[name=index]").val();
     map.set(index, value);
});
...
var data = {
//other values
"map": Array.from(map.entries()), //This is what I have found so far but 
                                  //this is what I believe needs to be changed
//Some more values
}
...
$.ajax({
   url: "/mapping",
   type: "POST",
   data: JSON.stringify(data),
   ...
});

As mentioned above, the changing into an array makes the deserialization fail, but otherwise the stringify makes the map into just: {} which I know is the expected behavior.

Is there anyway I can change this to make it do what I would like it to?

EDIT: This is the result of the stringify with the Array.from()

"{
  //values
  "map":[["0","value"],["1","another value"],["2","third value"]], 
  //more values
 }"

And like I mentioned above, if I just use "map":map then the resulting parsing is "map":{}

G. Blandin
  • 63
  • 7
  • 2
    Please post what your JSON actually looks like. – Roddy of the Frozen Peas Nov 30 '18 at 16:13
  • Looks you have key as string in JSON, but you are trying to assign it to Map – Ulad Nov 30 '18 at 16:36
  • @vlad324 That's a good point. Any idea how I can make sure that those are integers instead of strings after the Array.from(map.entries())? – G. Blandin Nov 30 '18 at 16:40
  • @G.Blandin try this one map.set(parseInt(index), value); never mind, stupid idea – Ulad Nov 30 '18 at 16:46
  • @vlad324 I found using Number($(this).find("input[name=index]").val()); made it a number so that works, however this still does not fix the deserialization issue. – G. Blandin Nov 30 '18 at 16:51
  • @G.Blandin I think you shoudn't use Array.from(map.entries()), becuase jackson expect your object to be look like this: { // other values "map" : { "1" : "val1", "2" : "val2", "3" : "val3" } } – Ulad Nov 30 '18 at 16:55
  • @G.Blandin and my idea about cast to int is stupid, because in resulting json it will be everything wrapped in " " – Ulad Nov 30 '18 at 16:56
  • @vlad324 The issue is that JSON.stringify does not support maps so when that is called on a nested map, the result is {}. – G. Blandin Nov 30 '18 at 16:58

1 Answers1

1

I just thought a little about your problem. We can't serialize JS Map() properly (Problems with JS map serialization), so my preposition is to change your code in this way:

...
var map = {}; // using object instead of map 
$("#mapBody tr").map(function () {
     var value = $(this).find( "input[name=value]").val();
     var index = $(this).find("input[name=index]").val();
     map[index] = value; // setting property of object
});
...
var data = {
//other values
"map": map, // using map object instead of array
//Some more values
}
...
$.ajax({
   url: "/mapping",
   type: "POST",
   data: JSON.stringify(data),
   ...
});

So resulting JSON looks like this:

'{"id":1,"map":{"1":"val1","2":"val2","3":"val3"},"otherProperty":"otherValue"}'

And this one is parsable to DTO with HashMap<Integer, String> map inside. Try it please and let me know if it works.

Ulad
  • 1,083
  • 8
  • 17
  • Thanks a bunch! This solved the issue. I didn't think just using an object would map correctly but it did. Thanks again! – G. Blandin Dec 03 '18 at 14:40