Wednesday, July 29, 2009

CF: ColdFusion Serialization via Java API

This is a topic that has found many posts. Here is my spin ;o) Most of the posts focus on the success of serializing ColdFusion components. Though cool, many ask the same question: Why do this?
Also to note is that ColdFusion has supported a mechanism to serialize complex data via WDDX for a long time (I believe since version 4).
However, in my case, the need was not for serialization components but rather for compact serialization. In other words, use as little space (bytes/data) as possible. In addition, I needed to easily save and retrieve this information from a database in a text based format. Oh, yes, and handle complex data objects such as structures and arrays.
WDDX, though usable, is very verbose and thus was out. Looking at the Java API and reading through posts I translated this, in the end, to two functions fSerialize and fDeserialize. You will need ColdFusion 8.0.1 or higher to make this work.

The fSerialize function:

<cffunction name="fSerialize" access="public" returntype="string"
hint="uses java byte streams and Base64 encoding to serialize CF objects, this can be used instead of WDDX tag CFML2WDDX">

<cfargument name="input" type="any" required="Yes" hint="the CF object to be serialized">
<cfscript>

var objByteStream = createObject(
"java", "java.io.ByteArrayOutputStream").init();
var objOutStream = createObject(
"java", "java.io.ObjectOutputStream").init(objByteStream);
var objSerialized =
"";
//turn CF object in argument to out stream
objOutStream.writeObject(Arguments.input);
objOutStream.close();
//take outstream and make bytearray
objSerialized = objByteStream.toByteArray();
//encoded it and return

return BinaryEncode(objSerialized,"Base64");
</cfscript>
</cffunction>


fDeserialize function:


<cffunction name="fDeserialize" access="public" returntype="any"
hint="uses Base64 encoded Java Byte Array and turns to CF object. This can be used instead of WDDX WDDX2CFML">

<cfargument name="Input" type="string" required="Yes" hint="the Base64 encoded ByteArray that used to be a CF object to be deserialized">
<cfscript>

var objSerialized =BinaryDecode(Arguments.input,
"Base64");
var inByteStream = createObject(
"java", "java.io.ByteArrayInputStream").init(objSerialized);
var objInStream = createObject(
"java", "java.io.ObjectInputStream").init(inByteStream);
var objCF = objInStream.readObject();
//return the read object
return objCF;
</cfscript>
</cffunction>

These function on average were using 50% of the storage that a comparable serialized WDDX object would, so they achieved their objective for me. They will work on small components (cfc) but I have not tried to serialize very complex cfcs.

Cheers,
-Bilal