Sep 09
ColdFusion 8 CFC serialization
Posted by James Netherton | Sunday 09 September 2007 11:09 AM | In ColdFusion
I was skimming through an old Java book and came across an example that used Java’s ObjectOutputStream to serialize objects. This got me thinking about a much trumpeted new feature in ColdFusion 8, the ability to serialize CFC objects.
Serialization enables you to ’save’ the state of an object, persist it and then read it back into memory at a later time. You can use the Java ObjectOutputStream class to serialize a ColdFusion component, together with all of its instance data.
First, I create a couple of simple CFC’s, I’ve left out many of the cffunction and cfargument attributes for quickness:
SimpleObject.cfc
<cfcomponent> <cfset variables.name = ""/> <cfset variables.age = 0/> <cfset variables.randomStuff = structNew()/> <cfset variables.address = ""/> <cffunction name="init"> <cfset variables.randomStuff["year"] = 2007/> <cfset variables.randomStuff["month"] = 9/> <cfset variables.randomStuff["day"] = 9/> <cfreturn this/> </cffunction> <cffunction name="getName"> <cfreturn variables.name/> </cffunction> <cffunction name="getAge"> <cfreturn variables.age/> </cffunction> <cffunction name="getRandomStuff"> <cfreturn variables.randomStuff/> </cffunction> <cffunction name="getAddress"> <cfargument name="address"/> <cfreturn variables.address/> </cffunction> <cffunction name="setName"> <cfargument name="name"/> <cfset variables.name = arguments.name/> </cffunction> <cffunction name="setAge"> <cfargument name="age"/> <cfset variables.age = arguments.age/> </cffunction> <cffunction name="setAddress"> <cfargument name="address"/> <cfset variables.address = arguments.address/> </cffunction> </cfcomponent>
Address.cfc
<cfcomponent> <cfset variables.street = ""/> <cfset variables.city = ""/> <cfset variables.country = ""/> <cfset variables.postcode = ""/> <cffunction name="init"> <cfreturn this/> </cffunction> <cffunction name="getStreet"> <cfreturn variables.street/> </cffunction> <cffunction name="getCity"> <cfreturn variables.city/> </cffunction> <cffunction name="getCountry"> <cfreturn variables.country/> </cffunction> <cffunction name="getPostCode"> <cfreturn variables.postcode/> </cffunction> <cffunction name="setStreet"> <cfargument name="street"/> <cfset variables.street = arguments.street/> </cffunction> <cffunction name="setCity"> <cfargument name="city"/> <cfset variables.city = arguments.city/> </cffunction> <cffunction name="setCountry"> <cfargument name="country"/> <cfset variables.country = arguments.country/> </cffunction> <cffunction name="setPostCode"> <cfargument name="postcode"/> <cfset variables.postcode = arguments.postcode> </cffunction> </cfcomponent>
Now I need to write code that will serialize instances of the above objects. First I must instantiate them and provide some dummy data:
cfcserialize.cfm
<cfscript>
simpleObject = createObject("component","simpleObject").init();
simpleObject.setName("James");
simpleObject.setAge(26);
addressObject = createObject("component","address").init();
addressObject.setStreet("Liverpool Street");
addressObject.setCity("London");
addressObject.setCountry("United Kingdom");
addressObject.setPostCode("ABC 123");
simpleObject.setAddress(addressObject);
</cfscript>
I can now serialize the simpleObject variable, which is of course an instance of the simpleObject class. Notice I only have to serialize simpleObject as it holds a reference to an address object.
cfcserialize.cfm continued
<cfscript>
fos = createObject("java","java.io.FileOutputStream").init(expandPath("./cfc.obj"));
oos = createObject("java","java.io.ObjectOutputStream").init(fos);
oos.writeObject(simpleObject);
oos.close();
</cfscript>
Run the script and if there were no errors, you should see a file named ‘cfc.obj’ within the directory where the script was executed from. Peek inside the file and you’ll see a bunch of junk which represents the CFC serialized data.
The next obvious step is to deserialize the data. For this we’ll be using the Java ObjectInputStream class.
cfcdeserialize.cfm
<cfscript>
fis = createObject("java","java.io.FileInputStream").init(expandPath("./cfc.obj"));
ois = createObject("java","java.io.ObjectInputStream").init(fis);
simpleObject = ois.readObject();
ois.close();
address = simpleObject.getAddress();
</cfscript>
The readObject method is used to retrieve the CFC instance back from the ‘cfc.obj’ file. Notice that once we have read the object back from the file, we can start using it immediately, as the code example does by retrieving a reference to the address object.
Now we can write out the dummy data we set earlier to prove that the serialization and deserialization process has really worked.
cfcdeserialize.cfm continued
<cfoutput> Name: #simpleObject.getName()#<br/> Age: #simpleObject.getAge()#<br/><br/> Street: #address.getStreet()#<br/> City: #address.getCity()#<br/> Country: #address.getCountry()#<br/> Post Code: #address.getPostCode()#<br/><br/> </cfoutput> <cfdump var="#simpleObject.getRandomStuff()#">
One thing you may want to do is wrap a cftry / cfcatch block around the serialization and deserializtion code so that you can close either the ObjectInputStream or ObjectOutputStream. You could potentially run into resource leaks if ColdFusion encounters and error and hasn’t reached the code that closes the object stream.
Overall, it’s quite a powerful technique. I just need to think of some use cases where it would come in handy…..
6 Comments
[Post comment]
1
Posted by David Stamm | Tuesday 20 November 12:11 PM
I had heard rumors of CF8’s serialization capabilites, but I had no idea how it easy it was to implement. Thanks for the excellent post!
No one in my development shop can think of an excuse to use serialization either. Good to know we can rely on the familiar Java API if we do think of something!
2
Posted by Brook Davies | Monday 03 December 10:12 AM
BUT it does not work with arrays in your CFC, de-serialization fails. Thats lame, seems to me like a have ass implementation. Who doesn’t use arrays? I hope this gets fixed so that it is useable in the real world and not just in a pretty test case with a simple CFC.
3
Posted by Peter | Monday 30 June 3:06 AM
Thanks for this.
4
Posted by Varsha | Tuesday 16 June 12:33 PM
while trying out the above eample, i got the following error
The error occurred in C:\Documents and Settings\varsha_magroriya\My Documents\CFExamples\Serilization\cfcserialize.cfm: line 19
17 : oos = createObject(“java”,”java.io.ObjectOutputStream”).init(fos);
18 :
19 : oos.writeObject(simpleObject);
20 : oos.close();
21 :
Please advise.
5
Posted by James Netherton | Tuesday 16 June 12:45 PM
What error message does CF give you (make sure you have robust debugging turned on)?
And you are using CF8, right?
6
Posted by James Netherton | Friday 04 December 12:30 PM
Just a note to say that the latest Adobe Hot Fix (4) for CF 8.01 has added support for serialization of Array, Datetime, Query and Java objects in CFCs.