Deserializing a JSON into a JavaScript object
JavascriptJsonDeserializationJavascript Problem Overview
I have a string in a Java server application that is accessed using AJAX. It looks something like the following:
var json = [{
"adjacencies": [
{
"nodeTo": "graphnode2",
"nodeFrom": "graphnode1",
"data": {
"$color": "#557EAA"
}
}
],
"data": {
"$color": "#EBB056",
"$type": "triangle",
"$dim": 9
},
"id": "graphnode1",
"name": "graphnode1"
},{
"adjacencies": [],
"data": {
"$color": "#EBB056",
"$type": "triangle",
"$dim": 9
},
"id": "graphnode2",
"name": "graphnode2"
}];
When the string gets pulled from the server, is there an easy way to turn this into a living JavaScript object (or array)? Or do I have to manually split the string and build my object manually?
Javascript Solutions
Solution 1 - Javascript
Modern browsers support JSON.parse()
.
var arr_from_json = JSON.parse( json_string );
In browsers that don't, you can include the json2
library.
Solution 2 - Javascript
The whole point of JSON is that JSON strings can be converted to native objects without doing anything. Check this link
You can use either eval(string)
or JSON.parse(string)
.
However, eval
is risky. From json.org:
> The eval function is very fast. > However, it can compile and execute any JavaScript program, > so there can be security issues. > The use of eval is indicated when the source is trusted and competent. > It is much safer to use a JSON parser. > In web applications over XMLHttpRequest, > communication is permitted only to the same origin that > provide that page, so it is trusted. > But it might not be competent. > If the server is not rigorous in its JSON encoding, > or if it does not scrupulously validate all of its inputs, > then it could deliver invalid JSON text that could be carrying dangerous script. > The eval function would execute the script, unleashing its malice.
Solution 3 - Javascript
Do like jQuery does! (the essence)
function parseJSON(data) {
return window.JSON && window.JSON.parse ? window.JSON.parse( data ) : (new Function("return " + data))();
}
// testing
obj = parseJSON('{"name":"John"}');
alert(obj.name);
This way you don't need any external library and it still works on old browsers.
Solution 4 - Javascript
You could also use eval()
but JSON.parse()
is safer and easier way, so why would you?
good and works
var yourJsonObject = JSON.parse(json_as_text);
I don't see any reason why would you prefer to use eval
. It only puts your application at risk.
That said - this is also possible.
bad - but also works
var yourJsonObject = eval(json_as_text);
Why is eval
a bad idea?
Consider the following example.
Some third party or user provided JSON string data.
var json = `
[{
"adjacencies": [
{
"nodeTo": function(){
return "delete server files - you have been hacked!";
}(),
"nodeFrom": "graphnode1",
"data": {
"$color": "#557EAA"
}
}
],
"data": {
"$color": "#EBB056",
"$type": "triangle",
"$dim": 9
},
"id": "graphnode1",
"name": "graphnode1"
},{
"adjacencies": [],
"data": {
"$color": "#EBB056",
"$type": "triangle",
"$dim": 9
},
"id": "graphnode2",
"name": "graphnode2"
}]
`;
Your server-side script processes that data.
Using JSON.parse
:
window.onload = function(){
var placeholder = document.getElementById('placeholder1');
placeholder.innerHTML = JSON.parse(json)[0].adjacencies[0].nodeTo;
}
will throw:
Uncaught SyntaxError: Unexpected token u in JSON at position X.
Function will not get executed.
You are safe.
Using eval()
:
window.onload = function(){
var placeholder = document.getElementById('placeholder1');
placeholder.innerHTML = eval(json)[0].adjacencies[0].nodeTo;
}
will execute the function and return the text.
If you run this on the serwer side and I replace this harmless function with one, that removes files from your website folder or does something harmful, then your app will get hacked. No errors/warnings will get thrown in this example.
You are NOT safe.
I was able to manipulate a JSON text string so it acts as a function which will execute on the server.
eval(JSON)[0].adjacencies[0].nodeTo
expects to process a JSON string but, in reality, we just executed a function on our server.
This could also be prevented if we server-side check all user-provided data before passing it to an eval()
function but why not just use the built-in tool for parsing JSON and avoid all this trouble and danger?
Solution 5 - Javascript
TO collect all item of an array and return a json object
collectData: function (arrayElements) {
var main = [];
for (var i = 0; i < arrayElements.length; i++) {
var data = {};
this.e = arrayElements[i];
data.text = arrayElements[i].text;
data.val = arrayElements[i].value;
main[i] = data;
}
return main;
},
TO parse the same data we go through like this
dummyParse: function (json) {
var o = JSON.parse(json); //conerted the string into JSON object
$.each(o, function () {
inner = this;
$.each(inner, function (index) {
alert(this.text)
});
});
}
Solution 6 - Javascript
And if you also want the deserialised object to have functions, you could use my small tool: https://github.com/khayll/jsmix
//first you'll need to define your model
var GraphNode = function() {};
GraphNode.prototype.getType = function() {
return this.$type;
}
var Adjacency = function() {};
Adjacency.prototype.getData =n function() {
return this.data;
}
//then you could say:
var result = JSMix(jsonData)
.withObject(GraphNode.prototype, "*")
.withObject(Adjacency.prototype, "*.adjacencies")
.build();
//and use them
console.log(result[1][0].getData());
Solution 7 - Javascript
If you paste the string in server-side into the html don't need to do nothing:
For plain java in jsp:
var jsonObj=<%=jsonStringInJavaServlet%>;
For jsp width struts:
var jsonObj=<s:property value="jsonStringInJavaServlet" escape="false" escapeHtml="false"/>;
Solution 8 - Javascript
I think this should help:
Also documentations also prove that you can use require() for json files: https://www.bennadel.com/blog/2908-you-can-use-require-to-load-json-javascript-object-notation-files-in-node-js.htm
var jsonfile = require("./path/to/jsonfile.json");
node = jsonfile.adjacencies.nodeTo;
node2 = jsonfile.adjacencies.nodeFrom;
node3 = jsonfile.adjacencies.data.$color;
//other things.