Serialize and Deserialize a Component in ColdFusion 8
I am working on a project where a requirement for serializing and deserializing a component came up. This is possible now with ColdFusion 8, since the underlying work was done (by Rakshith) to handle synchronizing sessions across a cluster. Nonetheless, there is no specific serialize or deserialize function for a CFC. Pete Frietag wrote about this as did Rakshith in earlier posts. My code below borrows pretty liberally from theirs but distills it into two CFC methods that I include a utility component to handle the serializing and deserializing. Also, I am not writing the serialized data to a file as in their examples, but passing you back Base64 data in the one case of the serialize() method. This was done so I could store the result in a database for reasons I won't get into here. One odd thing that came up when I tested this was that putting a returntype of "component" would not work on the deserialize method even though the result looks and behaves like a component instance, thus the returntype of "any." Below is the code for the two methods (keep in mind, I have only tested this on some simple CFC instances, share if you run into any issues).
<cffunction name="serializeCFC" access="public" output="false" returntype="String">
<cfargument name="cfc" type="component" required="true">
<cfset var byteOut = CreateObject("java", "java.io.ByteArrayOutputStream") />
<cfset var objOut = CreateObject("java", "java.io.ObjectOutputStream") />
<cfset byteOut.init() />
<cfset objOut.init(byteOut) />
<cfset objOut.writeObject(arguments.cfc) />
<cfset objOut.close() />
<cfreturn ToBase64(byteOut.toByteArray()) />
</cffunction>
<cffunction name="deserializeCFC" access="public" output="false" returntype="any">
<cfargument name="base64cfc" type="string" required="true" />
<cfset var inputStream = CreateObject("java", "java.io.ByteArrayInputStream") />
<cfset var objIn = CreateObject("java", "java.io.ObjectInputStream") />
<cfset var com = "" />
<cfset inputStream.init(toBinary(arguments.base64cfc)) />
<cfset objIn.init(inputStream) />
<cfset com = objIn.readObject() />
<cfset objIn.close()>
<cfreturn com />
</cffunction>
i can only seeing problems arising from this especially if you are storing the component in a database. what happens when you change the code in the component? obviously the stored serialized component is not going to get updated with the new code, thus resulting in hard to diagnose errors.
personally i think a better idea would be to dump the instance scope of the component and store that in the database instead. maybe i'm wrong, but this just feel creepy to me.
Which explains how to overcome the issues with Array's and Dates in case you haven't seen it yet
<cffunction name="getBean" returntype="model.beans.myBean">
<cfset var myBean = "">
<cfset myBean = createObject("component","model.beans.myBean").init()>
<cfreturn myBean>
</cffunction>
will work fine, whereas...
<cffunction name="getDeserialisedBean" returntype="model.beans.myBean">
<cfargument name="serialisedBean">
<cfset var myBean = "">
<cfset myBean = deSerialise(arguments.serialisedBean)>
<cfreturn myBean>
</cffunction>
... will return a null pointer error. Note it is NOT during the de-serialisation that the error occurs (as it would if the bean contained a cf array or query etc...) but actually during the return. If I change the returntype to "any" then the problem goes away. Now, it's easy to fix obviously, but nevertheless type checking is desirable.
Is this your experience?

