JSON with classes? - json

Is there a standardized way to store classes in JSON, and then converting them back into classes again from a string? For example, I might have an array of objects of type Questions. I'd like to serialize this to JSON and send it to (for example) a JavaScript page, which would convert the JSON string back into objects. But it should then be able to convert the Questions into objects of type Question, using the constructor I already have:
function Question(id, title, description){
}
Is there a standardized way to do this? I have a few ideas on how to do it, but reinventing the wheel and so on.
Edit:
To clarify what I mean by classes: Several languages can use classes (JAVA, PHP, C#) and they will often communicate with JavaScript through JSON. On the server side, data is stored in instances of classes, but when you serialize them, this is lost. Once deserialized, you end up with an object structure that do not indicate what type of objects you have. JavaScript supports prototypal OOP, and you can create objects from constructors which will become typeof that constructor, for example Question above. The idea I had would be to have classes implement a JSONType interface, with two functions:
public interface JSONType{
public String jsonEncode();//Returns serialized JSON string
public static JSONType jsonDecode(String json);
}
For example, the Question class would implement JSONType, so when I serialize my array, it would call jsonEncode for each element in that array (it detects that it implements JSONType). The result would be something like this:
[{typeof:"Question", id:0, title:"Some Question", description:"blah blah blah"},
{typeof:"Question", id:0, title:"Some Question", description:"blah blah blah"},
{typeof:"Question", id:0, title:"Some Question", description:"blah blah blah"}]
The javascript code would then see the typeof attribute, and would look for a Question function, and would then call a static function on the Question object, similar to the interface above (yes, I realize there is a XSS security hole here). The jsonDecode object would return an object of type Question, and would recursively decode the JSON values (eg, there could be a comment value which is an array of Comments).

You'll have to create your own serializer which detects Question (and other classes) and serializes them as constructor calls instead of JSON object notation. Note that you'll need a way to map an object to a constructor call. (Which properties come from which parameters?)
Everyone else: By classes he means functions used as constructors; I assume that he's trying to preserve the prototype.

Have you looked at JSON.NET? It can serialize/de-serialize .NET objects to JS and vice-versa. It is a mature project and I highly recommend it.
Also, if you could change the definition of your 'Question' function to take one object with properties instead of taking separate arguments, you can do something like this:
Working Demo
function Question(args)
{
this.id = args.id;
this.text = args.text;
}
Question.prototype.alertText = function() { alert(this.text); };
$(document).ready(
function()
{
var objectList =
{
'list' : [
{ 'id' : 1, 'text' : 'text one' }
,{ 'id' : 2, 'text' : 'text two' }
,{ 'id' : 3, 'text' : 'text three'}
],
'type' : 'Question'
};
var functionName = objectList['type'];
var constructor = window[functionName];
if(typeof constructor !== 'function')
{
alert('Could not find a function named ' + functionName);
return;
}
var list = objectList['list'];
$.each(list,
function()
{
var question = new constructor(this);
question.alertText();
}
);
}
);
On a side note, please prefix your .NET Interfaces with 'I' e.g. it should be IJsonType and not JsonType.
typeof is a keyword so specify the property name in quotes if you want to use it.

It's highly dangerous, but eval can process any text and execute it.
http://www.w3schools.com/jsref/jsref_eval.asp
But DON'T use it. May do something like pass over the params you want to pass into the constructor as a JSON object and call the constructor with it...
function Question({"id" : "val", "title", "mytitle", "description" : "my desc"}){
...
}

This might be useful.
http://nanodeath.github.com/HydrateJS/
https://github.com/nanodeath/HydrateJS
Use hydrate.stringify to serialize the object and hydrate.parse to deserialize.

Assuming you are using a Javascript client and a REST api backend and you are looking to define the rules for encoding a Method as JSON, you should probably consider using graphQL.
You could also look at my draft Specificaton for JSON-ND - that may give you simple representation: eg
Where the server publishes this specification:
{
"Question:POST(id:integer, title:string, description:string):string" :
"https://my.question.com:999/question"
}
Or perhaps a little less "C" style
{ "QuestionParam:Interface"[
"id:integer",
"title:string",
"description:string"
],
"Question:POST(QuestionParam[0,]):string" :
"https://my.question.com:999/question"
}
This means you can POST the following to https://my.question.com:999/question
{
"questions:Question": [
{id:0, title:"Some Question 1", description:"blah blah blah"},
{id:1, title:"Some Question 2", description:"blah blah blah"},
{id:2, title:"Some Question 3", description:"blah blah blah"}
]
}
And the server would respond with something like:
[
"answer 1",
"answer 2",
"answer 3",
]
You might even define a better return type say "Answer"
{
"Answer:Interface"[
"id:integer",
"answer:string"
],
"Question:POST(id:integer, title:string, description:string):Answer" :
"https://my.question.com:999/question:URI"
}
And the server would return:
{ "answers:Answer" :[
{"id":0, "answer":"Answer 1"},
{"id":1, "answer":"Answer 2"},
{"id":2, "answer":"Answer 3"}
]
}
on the client side, implement a JSON-ND interpreter similar to the example:
, include a Fetch call and you could use something like:
var questions = {
"questions:Question": [
{id:0, title:"Some Question 1", description:"blah blah blah"},
{id:1, title:"Some Question 2", description:"blah blah blah"},
{id:2, title:"Some Question 3", description:"blah blah blah"}
]
}
var answers = JSON_ND_Stringify(questions) ; //of course use an async call here

Related

Using Laravel, is there a way to run validation on one ajax call with data for multiple models?

Assuming one were to post multiple data sets of one model at the time through JSON, it is possible to insert these using Eloquent's Model::create() function. However in my case I'll also need to validate this data.
The Validator only takes a Request object as input, and as far as I've seen I can't create a new Request instance with only one model.
Assuming this would be the input data (JSON), and index is the value for the browser to know what data belongs to an what item (as they have no unique ID assigned at the point of creation)
[
{
"index" : 1,
"name" : "Item 1",
"value" : "Some description"
},
{
"index" : 2,
"name" : "Item 2",
"value" : "Something to describe item 2"
},
(and so on)
]
Every object in the root array needs to be ran through the same validator. The rules of it are defined in Model::$rules (public static array).
Would there be a way to run the validator against every item, and possibly capture the errors per item?
You can utilize Validator for manual validation:
...
use Validator;
...
$validator = Validator::make(
json_decode($data, true), // where $data contains your JSON data string
[
// List your rules here using wildcard syntax.
'*.index' => 'required|integer',
'*.name' => 'required|min:2',
...
],
[
// Array of messages for validation errors.
...
],
[
// Array of attribute titles for validation errors.
...
]
);
if ($validator->fails()) {
// Validation failed.
// $validator->errors() will return MessageBag with what went wrong.
...
}
You can read more about validating arrays here.

TypeScript / Angular 2 creating a dynamic object deserializer

So I am coming from a background of C# where I can do things in a dynamic and reflective way and I am trying to apply that to a TypeScript class I am working on writing.
Some background, I am converting an application to a web app and the backend developer doesn't want to change the backend at all to accommodate Json very well. So he is going to be sending me back Json that looks like so:
{
Columns: [
{
"ColumnName": "ClientPK",
"Label": "Client",
"DataType": "int",
"Length": 0,
"AllowNull": true,
"Format": "",
"IsReadOnly": true,
"IsDateOnly": null
}
],
Rows:[
0
]
}
I am looking to write an Angular class that extends Response that will have a special method called JsonMinimal which will understand this data and return an object for me.
import { Response } from "#angular/http";
export class ServerSource
{
SourceName: string;
MoreItems: boolean;
Error: string;
ExtendedProperties: ExtendedProperty[];
Columns: Column[];
}
export class ServerSourceResponse extends Response
{
JsonMinimal() : any
{
return null; //Something that will be a blank any type that when returned I can perform `object as FinalObject` syntax
}
}
I know StackOverflow isn't for asking for complete solutions to problems so I am only asking what is one example taking this example data and creating a dynamic response that TypeScript isn't going to yell at me for. I don't know what to do here, this developer has thousands of server-side methods and all of them return strings, in the form of a JSON or XML output. I am basically looking for a way to take his column data and combine it with the proper row data and then have a bigger object that holds a bunch of these combined object.
A usage case here after that data has been mapped to a basic object would be something like this.
Example:
var data = result.JsonMinimal() as LoginResponse; <-- Which will map to this object correctly if all the data is there in a base object.
var pk = data.ClientPK.Value;
I'm not exactly sure I understand, but you may want to try a simple approach first. Angular's http get method returns an observable that can automatically map the response to an object or an array of objects. It is also powerful enough to perform some custom mapping/transformation. You may want to look at that first.
Here is an example:
getProducts(): Observable<IProduct[]> {
return this._http.get(this._productUrl)
.map((response: Response) => <IProduct[]> response.json())
.do(data => console.log('All: ' + JSON.stringify(data)))
.catch(this.handleError);
}
Here I'm mapping a json response to an array of Product objects I've defined with an IProduct interface. Since this is just a "lambda" type function, I could add any amount of code here to transform data.

using JSON file to define array values in Node.js

In node.js my program app.js, i am defining array like this
var myList = [["SAHRUKH",47.49,"HIT"],["SALMAN",47.3,"FLOP"]];
console.log (myList)
It is giving output but i want an external JSON file to supply the parameter of myList array instead of me defining it hardcore
i have prepared a JSON file named ppm.json and change my code to
var myList = JSON.parse(fs.readFileSync('ppm.json', 'utf8'));
console.log (myList[1])
my ppm.json is this
{
"hero": "SAHRUKH",
"age": "47.49",
"lastpict": "HIT"
}
it giving me output as undefined in console. what is the problem. pls help.
Without more requirements it's hard to give a definitive answer, but one thing you can do:
app.js
var myList = require('./my_list.json');
console.log(myList);
my_list.json
[["SAHRUKH",47.49,"HIT"],["SALMAN",47.3,"FLOP"]]
You can use require() to load both JSON and JavaScript files.
For example,
myFile.json:
[["SAHRUKH",47.49,"HIT"],["SALMAN",47.3,"FLOP"]]
app.js:
var myList = require( './myFile.json' );
console.log (myList)
You're accessing your item wrong. You don't have an array you have an object.
Access your heros age like this:
myList['age']
You might also consider changing your file to look like this:
{
"SAHRUKH" : {
"age" : "47.49",
"lastpict" : "HIT"
}
}
In which case you'd get your hero's age like:
myList.SAHRUKH.age;
//Or Equivalently
myList['SAHRUKH']['age']; //The dot notation above is preferred though!
Or this
{ "heros" : [
{
"name" : "SAHRUKH",
"age" : "47.49",
"lastpict" : "HIT"
}
]}
In which case you'd get at age like:
myList.heros[0].age;
If you adjust your ppm.json file to look like:
[{
"hero": "SAHRUKH",
"age": "47.49",
"lastpict": "HIT"
}]
It should drop in and work directly. If you wanted to include multiple heroes, it would look like:
[
{
"hero": "SAHRUKH",
"age": "47.49",
"lastpict": "HIT"
},
{
"hero": "SALMAN",
"age": "47.3",
"lastpict": "FLOP"
}
]
Your resulting myList should be an array in the example you provided, with entry 0 being the first hero object (SAHRUKH) and 1 being the second, and so on.

Inserted Nested Item in Generated JSON in Groovy/Grails

I am using Grails 2.1 to render JSON as part of a RestFul API I created. The Domain class, based on a SqlServer table, looks like this:
String firstName
String lastName
String officialAddress1
String officalAddress2
String preferredAddress1
String preferredAddress2
(etc.). . .
Which returns JSON similar to this:
{
"firstName": "Joe",
"lastName": "Hill",
"officialAddress1": "1100 Wob Hill",
"officialAddress2": "Apt. # 3",
"preferredAddress1": "1100 Wobbly Lane.",
"preferredAddress2": "Apartment 3."
}
It is working fine but the client wants me to nest the results in this fashion:
{
"firstName": "Joe",
"lastName": "Hill",
preferredAddress {
"preferredAddress1": "1100 Wobbly Lane.",
"preferredAddress1": "Apartment 3."
},
officialAddress {
"officialAddress1": "1100 Wob Hill",
"officialAddress2": "Apt. # 3"
}
}
My question is since the domain class, and the database, are not structure in a way to return this type of nested result how can I easily change this in my returned JSON? Do I have to abandon my way of just regurgitating the JSON based on the database/domain object and do a custom converter of some kind?
i'm new to this stackoverflow thing and i hope i will not mess it but i think i know what you need. in your bootstrap.groovy file you find "def init = { servletContext -> " line
put in there something like this:
JSON.registerObjectMarshaller(YourDomainName) {
def returnArray = [:]
returnArray['firstName'] = it.firstName
returnArray['lastName'] = it.lastName
returnArray['preferredAddress'] = [it.preferredAddress1 ,it.preferredAddress2]
returnArray['officialAddress'] = [it.officialAddress1 ,it.officialAddress2]
return returnArray
}
now when you use the render with JSON as you did grails will look in bootstrap and
render the domain as you asked.
hope this helps
The posted answer was correct. I just wanted to add the slight change I made to get the exact results I needed:
Thanks! That did it. I originally that it would not work exactly how I needed it but I was wrong. I changed the syntax slightly to get the results I needed.
returnArray['preferredAddress'] = [address1: it.preferredAddress1?.trim(),
address2: it.preferredAddress2?.trim(),
address3: it.preferredAddress3?.trim(),
city: it.preferredCity,
state: it.preferredState,
postCode: it.preferredPostCode,
country: it.preferredCountry
]

Sencha Touch - Accessing Associated-Model Store JSON via Nested Looping

I've been lurking on Stack Overflow for quite some time now, and have found quite a number of very helpful answers. Many thanks to the community! I hope to be able to contribute my own helpful answers before too long.
In the meantime, I have another issue I can't figure out. I am using Sencha Touch to create a Web-based phone app and I'm having trouble using a nested loop to iterate through some JSON. I can grab the first level of data, but not the items nested within that first level. There is a somewhat related ExtJS thread, but I decided to create my own since ExtJS and Touch diverge in subtle yet important ways. Anyway, here is some code to show where I am:
JSON (truncated - the JSON is PHP/MYSQL-generated, and there are currently actually three sub levels with "title", all of which I can access. It's the sub level "items" through which I can't iterate):
{
"lists": [
{
"title": "Groceries",
"id": "1",
"items": [
{
"text": "contact solution - COUPON",
"listId": "1",
"id": "4",
"leaf": "true"
},
{
"text": "Falafel (bulk)",
"listId": "1",
"id": "161",
"leaf": "true"
},
{
"text": "brita filters",
"listId": "1",
"id": "166",
"leaf": "true"
}
]
}
]
}
Store:
var storeItms = new Ext.data.Store({
model: 'Lists',
proxy: {
type: 'ajax',
method: 'post',
url : LIST_SRC,
extraParams: {action: 'gtLstItms'},
reader: {
type: 'json',
root: 'lists'
}
}
});
Working Loop:
storeItms.on('load', function(){
var lstArr = new Array();
storeItms.each(function(i) {
var title = i.data.title;
lstArr.push(i.data.title);
});
console.log(lstArr);
});
Non-working Nested Loop:
storeItms.on('load', function(){
var lstArr = new Array();
storeItms.each(function(i) {
var title = i.data.title;
var id = i.data.id;
title.items.each(function(l) {
lstArr.push(l.data.text);
});
});
console.log(lstArr);
});
The non-working nested loop gives me the error "Cannot call method 'each' of undefined", in reference to 'title.items.each...'
I suspect this is because I've not set title to be a key to set up a key:value pair, so it just sees a list of strings...but I'm kind of at a loss.
I should mention that the store is populated via two Models that have been associated with one another. I know that the Store can access everything because I am able to do nested iterating via an XTemplate.
Any help will be much appreciated and hopefully returned to the community in kind before too long!'
-Eric
Eric, why the loop?
If your models are associated in the same way that the JSON is nested, then you should just be able to set autoLoad:true on the store, sit back and enjoy.
Anyway, on the assumption that you are needing these arrays for some other unrelated reason, the problem is that you are trying .each on
i.data.title.items
Surely you should be iterating through
i.data.items
Also, if the object is a model, you can use .get() instead of the data object:
var title = i.get('title);
Using new sencha touch 2 framework, you can create associations within the models exactly the same way how your json is returned.
Check Sencha Touch 2 Model Document which tells you the various config options on Model.
You may refer to this example of ST2 Nested List .
Hope this helps.
"title" is not a enumerable object, its a string. To iterate a string you'll need to split it to convert it into an array.
Also, instead of using Ext.each try a simple for (var x in obj) {} or for (var xc in obj.prop) {} If that works then the ext.each method should work as well but if ext cannot iterate the object it will just quietly fail.