YUI Library Home

YUI Library Examples: JSON Utility: Rebuilding class instances from JSON data

JSON Utility: Rebuilding class instances from JSON data

This example illustrates one method of serializing and recreating class instances by using the replacer and reviver parameters to JSON.stringify and JSON.parse respectively.

The CaveMan class

For this example, we'll use a class CaveMan, with a property discovered that holds a Date instance, and a method getName.

1YAHOO.util.Event.onDOMReady(function () { 
2 
3// set up some shortcuts 
4var Event = YAHOO.util.Event, 
5    Dom   = YAHOO.util.Dom, 
6    JSON  = YAHOO.lang.JSON, 
7    Demo; 
8 
9function CaveMan(name,discovered) { 
10    this.name       = name; 
11    this.discovered = discovered; 
12}; 
13CaveMan.prototype.getName = function () { 
14    return this.name + ", the cave man"
15
16 
17... 
view plain | print | ?

Add freeze and thaw static methods

We'll add the methods responsible for serializing and reconstituting instances to the CaveMan class as static methods.

1// Static method to convert to a basic structure with a class identifier 
2CaveMan.freeze = function (cm) { 
3    return { 
4        _class : 'CaveMan'
5        n : cm.name, 
6        d : cm.discovered // remains a Date for standard JSON serialization 
7    }; 
8}; 
9 
10// Static method to reconstitute a CaveMan from the basic structure 
11CaveMan.thaw = function (o) { 
12    return new CaveMan(o.n, o.d); 
13}; 
view plain | print | ?

Reference the methods in replacer and reviver functions

We'll create a demo.FreezeThaw namespace to hold our moving parts. In it, we'll add a method to pass to JSON.stringify that calls our custom serializer, and another method to pass to JSON.parse that detects the serialized structure and calls our thawing method.

1Demo = YAHOO.namespace('demo').FreezeThaw = { 
2 
3    cryo : function (k,o) { 
4        return (o instanceof CaveMan) ? CaveMan.freeze(o) : o; 
5    }, 
6 
7    revive : function (k,v) { 
8        // Check for cavemen by the _class key 
9        if (v instanceof Object && v._class == 'CaveMan') { 
10            return CaveMan.thaw(v); 
11        } 
12        // default to returning the value unaltered 
13        return v; 
14    } 
15}; 
view plain | print | ?

The data to be serialized

We'll create a CaveMan instance and nest it in another object structure to illustrate how the thawing process still operates normally for all other data.

1Demo.data = { 
2    count : 1, 
3    type  : 'Hominid'
4    specimen : [ 
5        new CaveMan('Ed',new Date(1946,6,6)) 
6    ] 
7}; 
view plain | print | ?

Thawing from the inside out and the Date instance

The reviver function passed to JSON.parse is applied to all key:value pairs in the raw parsed object from the deepest keys to the highest level. In our case, this means that the name and discovered properties will be passed through the reviver, and then the object containing those keys will be passed through.

We'll take advantage of this and apply YAHOO.lang.JSON.stringToDate to all string values, which will reconstitute Date instances when they match the iso8601 UTC format that JSON serializes Dates to by default.

1Demo = YAHOO.namespace('demo').FreezeThaw = { 
2 
3    cryo : function (k,o) { 
4        return (o instanceof CaveMan) ? CaveMan.freeze(o) : o; 
5    }, 
6 
7    revive : function (k,v) { 
8        // JSON.stringToDate turns strings in the iso8601 UTC format into Dates 
9        if (typeof v === 'string') { 
10            return JSON.stringToDate(v); 
11        } 
12        // Check for cavemen by the _class key 
13        if (v instanceof Object && v._class == 'CaveMan') { 
14            return CaveMan.thaw(v); 
15        } 
16        // default to returning the value unaltered 
17        return v; 
18    } 
19}; 
view plain | print | ?

Now when the reviver function is evaluating the object it determines to be a CaveMan, the discovered property is correctly containing a Date instance.

Choose your serialization

You'll note there are two freeze and thaw operations going on in this example. One for our CaveMan class and one for Date instances. Their respective serialization and recreation techniques are different. You are free to decide the serialized format of your objects. Choose whatever makes sense for your application.

Show and Tell

Now we add the event handlers to the example buttons to call JSON.stringify and parse with our example.cryo and example.revive methods, respectively.

1Event.on('demo_freeze','click',function (e) { 
2    Demo.jsonString = JSON.stringify(Demo.data, Demo.cryo); 
3 
4    Dom.get('demo_frozen').value = Demo.jsonString; 
5    Dom.get('demo_thaw').disabled = false
6}); 
7 
8Event.on('demo_thaw','click',function (e) { 
9    var x  = JSON.parse(Demo.jsonString, Demo.revive); 
10        cm = x.specimen[0]; 
11 
12    Dom.get('demo_thawed').innerHTML = 
13        "<p>Specimen count: " + x.count + "</p>"
14        "<p>Specimen type: " + x.type + "</p>"
15        "<p>Instanceof CaveMan: " + (cm instanceof CaveMan) + "</p>"
16        "<p>Name: " + cm.getName() + "</p>"
17        "<p>Discovered: " + cm.discovered + "</p>"); 
18}); 
19 
20}); // end of onDOMReady handler 
view plain | print | ?

Full Code Listing

1YAHOO.util.Event.onDOMReady(function () { 
2 
3var Event = YAHOO.util.Event, 
4    Dom   = YAHOO.util.Dom, 
5    JSON  = YAHOO.lang.JSON, 
6    Demo; 
7     
8Demo = YAHOO.namespace('demo').FreezeThaw = { 
9    data       : null
10    jsonString : null
11 
12    cryo : function (k,o) { 
13        return (o instanceof CaveMan) ? CaveMan.freeze(o) : o; 
14    }, 
15    revive : function (k,v) { 
16        // Turn anything that looks like a UTC date string into a Date instance 
17        if (typeof v === 'string') { 
18            return JSON.stringToDate(v);; 
19        } 
20        // Check for cavemen by the _class key 
21        if (v instanceof Object && v._class == 'CaveMan') { 
22            return CaveMan.thaw(v); 
23        } 
24        // default to returning the value unaltered 
25        return v; 
26    } 
27}; 
28 
29function CaveMan(name,discovered) { 
30    this.name       = name; 
31    this.discovered = discovered; 
32}; 
33CaveMan.prototype.getName = function () { 
34    return this.name + ", the cave man"
35
36 
37// Static methods to convert to and from a basic object structure 
38CaveMan.thaw = function (o) { 
39    return new CaveMan(o.n, o.d); 
40}; 
41// Convert to a basic object structure including a class identifier 
42CaveMan.freeze = function (cm) { 
43    return { 
44        _class : 'CaveMan'
45        n : cm.name, 
46        d : cm.discovered // remains a Date for standard JSON serialization 
47    }; 
48}; 
49 
50Demo.data    = { 
51    count : 1, 
52    type  : 'Hominid'
53    specimen : [ 
54        new CaveMan('Ed',new Date(1946,6,6)) 
55    ] 
56}; 
57 
58Event.on('demo_freeze','click',function (e) { 
59    Demo.jsonString = JSON.stringify(Demo.data, Demo.cryo); 
60 
61    Dom.get('demo_frozen').value = Demo.jsonString; 
62    Dom.get('demo_thaw').disabled = false
63}); 
64 
65Event.on('demo_thaw','click',function (e) { 
66    var parsedData = JSON.parse(Demo.jsonString, Demo.revive); 
67        cm = parsedData.specimen[0]; 
68 
69    Dom.get('demo_thawed').innerHTML = 
70        "<p>Specimen count: " + parsedData.count + "</p>"
71        "<p>Specimen type: " + parsedData.type + "</p>"
72        "<p>Instanceof CaveMan: " + (cm instanceof CaveMan) + "</p>"
73        "<p>Name: " + cm.getName() + "</p>"
74        "<p>Discovered: " + cm.discovered + "</p>"
75}); 
76 
77}); 
view plain | print | ?

Configuration for This Example

You can load the necessary JavaScript and CSS for this example from Yahoo's servers. Click here to load the YUI Dependency Configurator with all of this example's dependencies preconfigured.

YUI Logger Output:

Note: Logging and debugging is currently turned off for this example.

Reload with logging
and debugging enabled.

More JSON Utility Resources:

Copyright © 2011 Yahoo! Inc. All rights reserved.

Privacy Policy - Terms of Service - Copyright Policy - Job Openings