Question

I have an object model that I want to be able to save. I am going to export it to JSON and then read it back in as JSON.

Saving to JSON is easy. Just use this: JSON.stringify(this).

Loading from JSON isn't as simple.

  • We can't just use this = JSON.parse(someJson) because the methods wont be attached.
  • Using something like lang.mixin(this, JSON.parse(someJson)) will get the functions but objects that are

Photo Class:

define([...], function(...){
    return declare(null, {
        name: ..., // String
        url:..., // String
        complexProperty:..., // Some other class

        someFunction1: function(...){..},
        someFunction2: function(...){..},
        someFunction2: function(...){..}
    }
));

Photo Album Class:

define([...], function(...){
    return declare(null, {
        photos: [], /* Array of type Photo (see above) */
        someOtherProperty: ...,
        someOtherProperty: ...,

        someFunction1: function(...){..},
        someFunction2: function(...){..},
        someFunction2: function(...){..},

        toJson: function(){
            return JSON.stringify(this);    // From dojo/json
        }

        loadFromJson: function(jsonIn){
            // How to do this?
        }, 

        /* This doesn't work because methods will be overridden */
        loadFromJson1: function(jsonIn){
            this = JSON.parse(someJson);
        }, 

        /* This insures that my methods are kept intact but my childrens methods arn't (ie: the array of photos) */
        loadFromJson2: function(jsonIn){
            lang.mixin(this, JSON.parse(someJson));
        }, 

        /* This seems like an aweful lot of work.  Any better ways to do this? */
        loadFromJson3: function(jsonIn){
            this.someOtherProperty = jsonIn.someOtherProperty;
            this.someOtherProperty = jsonIn.someOtherProperty;
            foreach(jsonIn.photos: photoJson){
                var newPhoto = new Photo();
                newPhoto.loadfromJson(photoJson);
                this.photos.add(newPhoto);
            }
            ... All other properties set recursively.  All things in model now need this method ...
        }
    }
));
Was it helpful?

Solution

I think you would be better off returning a JSON object that contains just the data you need to serialize, not the whole class. Then your loadFromJson method would be a little easier to implement, and you wont be sending unnecessary data over the network. Example toJson():

toJson: function() {
    return JSON.stringify({
        photos: this.photos,
        someImportantProp: this.someImportantProp,
        anotherProp: this.anotherProp
    });
}

OTHER TIPS

JSON is not the same thing as a JavaScript object, in fact, it's only a subset. JSON only allows arrays, objects and of course basic types like Strings, booleans, numbers and null. You can find the entire specification here.

If you really want to keep the functions you can use the eval() function, but this is not really recommended, because it indeed parses those functions. If the evaluated content contains malicious input, then that is being executed as well.

For example:

eval("myObj = { getSum: function getSum(a, b) { return a + b; } }");
myObj.getSum(1, 2); // Returns 3

You can better attempt to save the state of the object (name and url for example) and rebuild it once you parse it again, that is what happens in other programming languages as well. For example, if you're serializing/deserializing an object in Java.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top