Better ActionScript JSON encode/decode

JSON (Javascript Object Notation)  is a kind of serialization method for objects. It represents your objects as strings and you can send/receive those strings to any other software party that can understand JSON.

JSON is almost perfect as a data interchange format standard and nowadays it is widely accepted.

There are some popular alternatives like XML for example, but XML is bloated. XML is parsed faster than JSON but it seems that more people are willing to sacrifice processing time instead of bandwidth. A lesser known alternative is Entity. Entity is encoded/decoded faster than JSON and it`s even smaller but it`s less readable than JSON… So let`s stick with JSON.

It`s a pity that Adobe Flex until version 3.6 did not include built in support for JSON encoding/decoding so you have to use an external library to achieve that. I was using as3corelib and it was fine until i began using dynamic objects. The problem seems to be in JSON.encode. it doesn`t work with dynamic properties.  I googled and i found that others were having the same issue to but i could not find any solutions so i had to write my own and drop as3corelib entirely…

JSON decoding is pretty simple.

Javascript can ‘understand’ JSON strings without having to write an encoder/decoder. the name implies it… So we ExternalInterface to call a dummy javascript anonymous function that just return our object back. ?

public static function json_decode( data:String ):*
{
return ExternalInterface.call("function(){return " + data + "}");
}

JSON encoding is a little more complicated. We have to inspect all the properties of the given object and return their JSON representation. This function has to be recursive because an object can be compound of another object and so on.

public static function json_encode(obj:*):String
{
if(obj == null) return null;
var end:String;
var st:String;
var str:String = "";
////trace(flash.utils.getQualifiedClassName(obj));
if(obj is Number || obj is int || obj is Boolean )
{
end = "";
st = "";
str+=st;
str+=obj;
str+=end;
return str;
}
else
if(obj is String || obj is Date || (obj as String)!=null)
{
end = "\"";
st = "\"";
str+= st;
if(obj is Date)
obj = DateField.dateToString(obj,"YYYY-MM-DD");
//let`s escape the string

obj = obj.split('\t').join('   ');
obj = obj.split('\n').join('\\n');
obj = obj.split('\f').join('\\f');
obj = obj.split('\r').join('');
obj = obj.split('"').join('\\"');
obj = obj.split('\\').join('\\\\');

str+=obj;
str+=end;
return str;
}
else
if(flash.utils.getQualifiedClassName(obj)== "Array")
{
end = "]";
st = "[";
str +=st;
for(var i=0;i<obj.length;i++)
{
str+=(i==0?"":",")+json_encode(obj[i]);
}
str +=end;
return str;
}else
if(obj is Object )
{
end = "}";
st = "{";
str +=st;
var o_info = (ObjectUtil.getClassInfo(obj)).properties;
for(var i=0;i< o_info.length;i++)
{
////trace("property: "+o_info[i].localName);
str+=(i==0?"":",")+"\""+o_info[i].localName+"\""+":"+json_encode(obj[o_info[i].localName]);
}
str +=end;
return str;
}else
if(obj is Function) return "";

return "";
}

The recursive solution is faster than a possible iterative solution, but it consumes a lot of stack memory. Let`s hope you don`t get a Stack Overflow error.

Enjoy!

Leave a Reply

Your email address will not be published. Required fields are marked *