Serialize and Deserialize a Component in ColdFusion 8
Posted on Sep 18, 2008
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 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() />
<cfreturn com />
let me play devil's advocate for a minute and ask why you would even want to do something like this?
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.
Posted By tony petruzzi / Posted on 09/18/2008 at 1:10 PM
I am not advocating doing this as a standard solution (and, fwiw, we didn't advocate it even in the case where we are implementing it) but there are cases where serializing a CFC would be useful. Also, you can serialize a fully composed object this way while if you simply stored properties you couldn't easily handle that.
Posted By Brian Rinaldi / Posted on 09/18/2008 at 6:24 PM
Also this will serialize the entire object graph (all dependent components), which will vastly multiply the issue of any changes to any dependent components invalidating the whole serialized object. It also does not currently support arrays, queries, dates, or Java objects. Basically, in its current incarnation, CFC serialization is fraught with issues.
Posted By Brian Kotek / Posted on 09/18/2008 at 6:25 PM
@Brian - obviously if the code changes, that is an issue...I think anyone who would be storing serialized objects would be aware of the issue. Like I said in my prior comment, this isn't an everyday type of need. Nonetheless, thanks for the info about the issues. I should ping you offline for some details as I mentioned to the client that since I hadn't tested this on very complex object data, I saw it as a huge breakage point. That kind of info is exactly what I had hoped for by posting it.
Posted By Brian Rinaldi / Posted on 09/18/2008 at 6:32 PM
I think Brian K covered most of the pitfalls. Serialization can be really useful when working with distributed systems or systems with limited resources. Serializing an object graph for 15 seconds and putting somewhere other than memory like flash memory or something slightly more stable can be a huge boon for micro systems. That being said these applications are not web applications, and certainly not CFML apps. Obviously Brian has a use for it though and I hope to hear more about it. I think it would be great if it worked better in ColdFusion. I'd love to use it to Serialize the object graph for Fusebox. This would offer some very nice performance gains on start-up in production.
Posted By Adam / Posted on 09/19/2008 at 7:43 AM
hey Brian, I was just researching this again today and came across http://www.oscararevalo.com/index.cfm/2008/7/28/Overcoming-CFC-Serialization-Issues-Using-Java
Which explains how to overcome the issues with Array's and Dates in case you haven't seen it yet
Posted By Don Q / Posted on 09/21/2008 at 10:41 AM
I've noticed that a de-serialised object causes null pointer errors when it is returned from a function with a fixed returntype, e.g.
<cffunction name="getBean" returntype="model.beans.myBean">
<cfset var myBean = "">
<cfset myBean = createObject("component","model.beans.myBean").init()>
will work fine, whereas...
<cffunction name="getDeserialisedBean" returntype="model.beans.myBean">
<cfset var myBean = "">
<cfset myBean = deSerialise(arguments.serialisedBean)>
... 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?
Posted By Andy Bellenie / Posted on 10/02/2008 at 5:50 AM
Posted By Brian Rinaldi / Posted on 10/02/2008 at 5:58 AM
Try this scenario:
Serialize a object on one CF8 server. Store the serialized string in a file.
Try to deserialize the string in the file on a different CF8 server.
Looks like - if the CF8 versions (OS level or update level) are not same on both servers - deserialize will fail.
Posted By Srikanth / Posted on 03/11/2011 at 2:16 PM
Beware. We have discovered issues with serializing and deserializing an object that was duplicate()'ed.
We were getting back the parent class! Instead of user object we got the parent class of person!
Insane. CF8 only. Was fine in CF9.
Posted By Will B. / Posted on 06/27/2012 at 2:47 PM