21

My REST controller expects request input of the following format, which it successfully converts to a Java object containing a Map and a String as parameters:

{ 
"myMap" : { 
    "key1": "value1", 
    "key2": "value2", 
    "key3": "value3"},
"myString": "string value"
}

I am getting my data from an html form like so:

var myMap = new Map();
var String = document.getElementById('String').value;
for (var i = 0 ; i<anArray.length ; i++){
    var input = document.getElementsByClassName('input_' + (i+1));
    for (var j = 0 ; j<3 ; j++){
        if (input[j].checked){
            myMap.set(input[j].name, input[j].id);
        }
    }
}

Basically, this code boils down to:

var myMap = new Map();
myMap.set("key1", "value1");
myMap.set("key2", "value2");
myMap.set("key3", "value3");

This results in a map containing {key1 => value1, key2 => value2, etc} and a String. I have been trying to turn this into a json string like so, but it doesn't seem to work:

var myJson = {};
myJson.myMap = myMap;
myJson.myString = myString;
var json = JSON.stringify(myJson);

However, I am ending up with the following string: `{"myMap":{},"String":"myString"}' . So I probably have to do something different to stringify a map, but nothing I try is working.

Can anyone help me out?

3
  • What is repetitie ? Also please provide a minimal reproducible example Commented Jun 24, 2017 at 20:00
  • Sorry. I forgot to change it, I corrected it to myMap Commented Jun 24, 2017 at 20:01
  • 2
    People may land on this page when they instead really want: const obj1 = Object.fromEntries(map1);, which was the best answer for me. stackoverflow.com/a/55537385/470749 Commented May 18, 2021 at 22:36

7 Answers 7

20

Using ES6 syntax, and especially if you have nested maps (otherwise Idan Dagan's answer is simpler), you can use the JSON.stringify()'s second argument, the reducer, as follows:

JSON.stringify(myMap, (key, value) => (value instanceof Map ? [...value] : value));

Sign up to request clarification or add additional context in comments.

2 Comments

Perfect! I was trying to use the ES 2019 feature Object.fromEntries(map) but realized this is only useful if non-nested maps need to be compared. I have to deal with a nested map and you solution works like a charm!
i get an empty list as the result from this
14

You can write a short conversion function to make a map into an object that can be stringified.

console.clear()

function mapToObj(map){
  const obj = {}
  for (let [k,v] of map)
    obj[k] = v
  return obj
}

const myMap = new Map();
myMap.set("key1", "value1");
myMap.set("key2", "value2");
myMap.set("key3", "value3");

const myString = "string value"

const myJson = {};
myJson.myMap = mapToObj(myMap);
myJson.myString = myString;
const json = JSON.stringify(myJson);

console.log(json)

Here is a version that that presumably would work where Map exists but some other ES6 constructs do not (though, this seems like an editor settings issue).

console.clear()

function mapToObj(map){
  var obj = {}
  map.forEach(function(v, k){
    obj[k] = v
  })
  return obj
}

var myMap = new Map();
myMap.set("key1", "value1");
myMap.set("key2", "value2");
myMap.set("key3", "value3");

var myString = "string value"

var myJson = {};
myJson.myMap = mapToObj(myMap);
myJson.myString = myString;
var json = JSON.stringify(myJson);

console.log(json)

5 Comments

myMap is not defined within the function block and the map param of the function is not used. I think you meant to use of map and the code just runs because of the definition of myMap defined outside the function.
I have been trying this. However, IntelliJ keeps giving me an error saying "let are not supported by the current javascript version". Any way to fix that?
@I.Brok You have a version that supports Map but not let? Interesting. I'll convert it.
@I.Brok in IntelliJ go to settings -> languages -> javascript -> Ecmascript 6 from the dropdown.
@ Bert Evans and @Juan Thanks for the help! Changing the version to Ecmascript 6 did the trick. But still thank you for converting it Bert. It is always good to learn multiple ways.
6

JSON stringification has the special behavior for objects, arrays and functions.

For example:

JSON.stringify( function(){} ); // output: undefind
JSON.stringify( [2,undefined,function(){}, 5] ); //output: "[2,null,null,5]"

One way for solving that is to define a toJSON() method for it that returns a JSON-safe version of the object.

var myJson = {};
myJson.toJson = function() {
    return {  /* what ever you need*/}
}

Second, and more simple, using ES6 syntax:

JSON.stringify([...myMap]);

Comments

4

This is the best way in es6

const myMap = new Map();
myMap.set("key1", "value1");
myMap.set("key2", "value2");
myMap.set("key3", "value3"); 

JSON.stringify(Object.fromEntries(myMap))

Comments

3

You can use Array.prototype.reduce along with spread notation to tersely convert your map to the format you need.

var myMap = new Map();
myMap.set("key1", "value1");
myMap.set("key2", "value2");
myMap.set("key3", "value3");
var myString = "string value";

function mapToObj (map) {
  return [...map].reduce((acc, val) => {
    acc[val[0]] = val[1];
    return acc;
  }, {});
}

const json = JSON.stringify({
  myMap: mapToObj(myMap),
  myString: myString
});

console.log(json);

Comments

2

This hack will do the job (but it's a global override and must be used carefully):

  Map.prototype.toString = function() {

    let result = {};

    this.forEach((key, value) => { result[key] = value;});

    return JSON.stringify(result);
  };

Comments

0

Instead of a Map you can initialize myMap as follows

myMap = {};

Set elements in it as -

if (input[j].checked){
        myMap[input[j].name] = input[j].id;
}

Finally while converting you can do the following -

myJSON = {};
myJSON.myMap = JSON.stringify(myMap);
myJSON.myString = "StringValue";
var json = JSON.stringify(myJSON);

1 Comment

Thanks a bunch. This also works fine. I had tried it before, but made the mistake of using myMap.[input[j].name] . Now all I need to consider which way I suits best and whether I really need it to be a Map, or whether it's fine to let it be an Object. If anything, I understand that difference between Map and Object better now, and that is always a good thing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.