I'm unclear how serialization/de-serialization is supposed to work on typed objects in JavaScript. For example, I have a "MapLayer" object that contains various members and arrays. I have written (but not yet tested) the following code to attempt to serialize it:
MapLayer.prototype.serialize = function() {
var result = "{tileset:tilesets." + tilesets.getTilesetName(this.tileset) + ",columns:" + this.columns + ",rows:" + this.rows +
",offsetX:" + this.offsetX + ",offsetY:" + this.offsetY + ",currentX:" + this.currentX + ",currentY:" + this.currentY +
",scrollRateX:" + this.scrollRateX + ",scrollRateY:" + this.scrollRateY + ",virtualColumns:" + this.virtualColumns + ",virtualRows:" + this.virtualRows +
",tiles:\"" + this.encodeTileData2() + "\"";
for(key in this)
{
if(this[key] instanceof Sprite)
result += "," + key + ":" + this[key].serialize();
}
return result;
}
My question is, how is the resulting object supposed to get deserialized as a MapLayer object rather than as a generic Object. And how are all the Sprite instances supposed to get deserialized as sprites. Should I be using "new MapLayer()" instead of "{}"? Or am I simply supposed to include the prototype and constructor properties of the object in the serialization? Anything else I'm missing? Am I doing this a stupid way? There are 2 reasons I'm not using generic serialization/de-serialization code:
Edit: Excuse my lack of proper terminology; JavaScript is one of my less expert languages. What I mean when I said "Typed Object" is an object with a constructor. In this example, my constructor is:
function MapLayer(map, tileset, columns, rows, virtualColumns, virtualRows, offsetX, offsetY, scrollRateX, scrollRateY, priority, tileData) {
this.map = map;
this.tileset = tileset;
this.columns = columns;
this.rows = rows;
this.offsetX = offsetX;
this.offsetY = offsetY;
this.currentX = offsetX;
this.currentY = offsetY;
this.scrollRateX = scrollRateX;
this.scrollRateY = scrollRateY;
if(tileData.length < columns * rows * 2)
this.tiles = DecodeData1(tileData);
else
this.tiles = DecodeData2(tileData);
this.virtualColumns = virtualColumns ? virtualColumns : columns;
this.virtualRows = virtualRows ? virtualRows : rows;
}
Edit 2: Taking the code from Šime Vidas' answer, I have added a related object called "Device":
function Device( description, memory ) {
this.description = description;
this.memory = memory;
}
function Person( name, sex, age, devices ) {
this.name = name;
this.sex = sex;
this.age = age;
this.devices = devices;
}
Person.deserialize = function ( input ) {
var obj = JSON.parse( input );
return new Person( obj.name, obj.sex, obj.age, obj.devices );
};
var device = new Device( 'Blackberry', 64);
var device2 = new Device( 'Playstation 3', 600000);
var person = new Person( 'John', 'male', 25, [device, device2] );
var string = JSON.stringify(person);
console.log( string );
var person2 = Person.deserialize( string );
console.log( person2 );
console.log( person2 instanceof Person );
Now the question is how best to incorporate such dependent objects, because once again, the "type" (prototype?) of the object gets lost by JSON. Instead of running the constructor, why don't we simply change the serialize and the de-serialize functions to ensure that the object only needs to be constructed once like this instead of created and copied?
Person.prototype.serialize = function () {
var obj = this;
return '({ ' + Object.getOwnPropertyNames( this ).map( function ( key ) {
var value = obj[key];
if ( typeof value === 'string' ) { value = '"' + value + '"'; }
return key + ': ' + value;
}).join( ', ' ) + ',"__proto__":Person.prototype})';
};
Person.deserialize = function ( input ) {
return eval( input );
};
Edit 3: Another problem I have is that JSON doesn't seem to work in IE9. I'm using this test file:
<html>
<head>
<title>Script test</title>
<script language="javascript">
console.log(JSON);
</script>
</head>
</html>
And the console outputs:
SCRIPT5009: 'JSON' is undefined
test.html, line 5 character 1
Edit 4: To correct the JSON problem I must include the correct DOCTYPE tag at the beginning.
To serialize an object means to convert its state to a byte stream so way that the byte stream can be reverted back into a copy of the object. A Java object is serializable if its class or any of its superclasses implements either the java. io. Serializable interface or its subinterface, java.
In JavaScript, for example, you can serialize an object to a JSON string by calling the function JSON. stringify() . CSS values are serialized by calling the function CSSStyleDeclaration.
stringify() ignores functions/methods when serializing. JSON also can't encode circular references. Most other serialization formats have this limitation as well but since JSON looks like javascript syntax some people assume it can do what javascript object literals can.
The convert() function uses keys() and map() method to convert the serialize object to query string.
For a start, here is a simple example of custom serialization / deserialization:
function Person( name, sex, age ) {
this.name = name;
this.sex = sex;
this.age = age;
}
Person.prototype.serialize = function () {
var obj = this;
return '{ ' + Object.getOwnPropertyNames( this ).map( function ( key ) {
var value = obj[key];
if ( typeof value === 'string' ) { value = '"' + value + '"'; }
return '"' + key + '": ' + value;
}).join( ', ' ) + ' }';
};
Person.deserialize = function ( input ) {
var obj = JSON.parse( input );
return new Person( obj.name, obj.sex, obj.age );
};
Usage:
First, we create a new instance object:
var person = new Person( 'John', 'male', 25 );
Now, we serialize that object into a string using the Person.prototype.serialize
method:
var string = person.serialize();
This will give use this string:
{ "name": "John", "sex": "male", "age": 25 }
Finally, we deserialize that string using the Person.deserialize
static method:
var person2 = Person.deserialize( string );
Now, person2
is an instance of Person
and contains the same property values as the original person
instance.
Live demo: http://jsfiddle.net/VMqQN/
Now, while the Person.deserialize
static method is required in any case (it uses JSON.parse
internally, and invokes the Person
constructor to initialize a new instance), the Person.prototype.serialize
method on the other hand, is only needed if the built-in JSON.stringify
static method doesn't suffice.
In my example above var string = JSON.stringify( person )
would get the job done too, so a custom serialization mechanism is not needed. See here: http://jsfiddle.net/VMqQN/1/ However, your case is more complex, so you'll need to define a custom serialization function.
If you look at the ST-JS (http://st-js.org) project, it allows to create your object graph in Java on the server side, serialize it in JSON, and deserialize it on the client side (Javascript) in a typed manner, i.e. the objects will be instantiated using their constructor and you can call methods on the created objects.
To use ST-JS you should write your client code is Java, that is converted almost one-to-one in Javascript.
The AJAX/JSON chapter on the home page of the site explains you how to parse a JSON string while keeping the type information.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With