Serializing / Deserializing in ColdFusion 9

Today I was asked a question about serializing a CFC. Someone wanted to serialize the CFC for later use outside the current process.

Prior to ColdFusion 9, serializing a complex object in a way that could be deserialized back to a usable object within the runtime could be done by diving a bit down into the underlying java. This could only be done with CFCs as of CF8 as the serializable interface was added at that time. For those of you not on CF9, the code below can be used to serialize/deserialize objects in ColdFusion.

<cfscript>
function serialize(myObject) {
     // Create the underlying ByteArrayOutputStream
     byteOut = CreateObject("Java", "java.io.ByteArrayOutputStream");
     byteOut.init();
        
     // Create the ObjectOutputStream to which the object will be written
     objOut = CreateObject("Java", "java.io.ObjectOutputStream");
     objOut.init(byteOut);
    
     // Write the object to and close the stream
     objOut.writeObject(arguments.myObject);
     objOut.close();
    
     return toBase64(byteOut.toByteArray());
    }

    function deserialize(mySerializedObject) {
     // Create the underlying ByteArrayInputStream
     byteIn = CreateObject("Java", "java.io.ByteArrayInputStream");
     byteIn.init(binaryDecode(arguments.mySerializedObject,'base64'));
        
     // Create the ObjectInputStream to which the object will be read in from
     objIn = CreateObject("Java", "java.io.ObjectInputStream");
     objIn.init(byteIn);
    
     return objIn.readObject();
    }
</cfscript>

With ColdFusion 9, this is much simpler, but unless you've already looked at the other 200 new functions for CF9 you probably haven't seen this. With the new ObjectLoad() and ObjectSave() methods, now all you need is the following:

<cfscript>
    function serialize(myObject) {
     return toBase64(objectsave(myObject));
    }

    function deserialize(mySerializedObject) {
     return objectload(tobinary(mySerializedObject));
    }
</cfscript>

Heck, you don't really need the UDF's if you can remember to use two functions for this. :)

Now you can easily serialize an array, CFC, query, java object, structure... pretty much any object in ColdFusion.

Why would you want to do this? How about caching objects to your database to be retrieved later? Or maybe you want to store a CFC as a string in a form field... Those might be crazy, or you may have the need for something that crazy right now. You decide what cool things you want to do with this power. :)

Jason

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Ryan Vikander's Gravatar Couldn't you just use SerializeJSON() to serialize the struct?
# Posted By Ryan Vikander | 5/4/10 5:43 PM
salvatore fusto's Gravatar A question: suppose i've to persist an object in the session scope (may be a user obj for login, or even a complex cart in an e-commecr app, what is the best: persist the object or the serialized object?
# Posted By salvatore fusto | 5/5/10 4:46 AM
Jason Delmore's Gravatar SerializeJSON will work for simple objects like structs, queries, arrays, but it will not work for a CFC or a java object. So yes for ColdFusion data types and a big no for complex objects. :)

The ObjectLoad/ObjectSave methods can handle pretty much anything you throw at them.

@Salvatore - the benefit of serializing in this way is that it gives you a string representation of the object. If you are stroring something in memory (ie. the session scope), there is no benefit to this. But if you want to store an object in a string form because the transport mechanism or storage mechanism does not allow for binary representations, then you will need to serialize the object (convert it to a string.) The example I have actually used in the past was to pass a CFC along in a form field. This allowed me to continue making changes to a data object, without persisting those changes until the end of a multi-page form entry. If the user dropped off, it saved the system the hassle of processing anything, or needing to deal with partial data or a roll-back. Plus, it was dead simple to do. :)

Jason
# Posted By Jason Delmore | 5/6/10 4:05 PM
Justin Scott's Gravatar I'm curious if anyone has tried to use this sort of object serialization to move an object (CFC) between one server and another, or persist an object into storage and then deserialize it much later.

From my own basic tests, it would appear that ColdFusion doesn't serialize the entire CFC and all of its properties and methods into a string, but only takes the values of properties that are different from the defaults and uses that as the basis for serialization. It also appears to include some sort of pointer back to the original CFC file on the server as the point to work from when deserializing back into an object in memory.

For example, when you serialize a CFC into a string and then save it to a file on disk, then read that data from disk and deserialize it in a CFM file in another folder, it will work properly as long as the original CFC file is in place on the hard drive. So, it is possible to persist data across requests in storage. However, if that original CFC file is removed prior to the deserialization, ColdFusion throws a nasty "Null pointer exception" error at you. Even if a copy of that CFC is placed in the folder where the deserialize code lives, it will still go looking for that original file and error if it's not there. It appears that a pointer to that original CFC file is stored with the serialized data.

Another interesting point, if the signature of the original CFC changes (i.e. properties or methods added or changed), the deserialized version of your stored serialized CFC will magically contain any new methods or functions that have been added, and be void of any properties or methods that have been removed. Essentially what it's doing upon deserialization is looking at the pointer to the original CFC file, instantiating a copy of it, and then setting any property values that were set in the original pre-serialized version to override the defaults of the new instantiated instance.

I haven't tried placing a copy of the same CFC in the same location on a different server or checked it across server restarts yet, but I'm curious if others have and what results they might have had.

I have a situation where I'd like to serialize a CFC and store it in a file, and it could live there for months before its loaded again, and it may even be loaded on a different server. I'm not certain this particular serialization method will work for me, so I may need to ship the data into and out of XML prior to saving to disk, but if there is a way the CFC and its child objects can be easily serialized and reloaded natively that would be ideal. Any thoughts?
# Posted By Justin Scott | 6/6/11 1:34 AM
Tiki Howpu's Gravatar Hi. thanks for posting this Jason.

I've have problem with serializing / deserializing.
We want to deserialize objects created (serialized) with ColdFusion 8 in ColdFusion 9.
Because of the different JVM versions, a "serialVersionUID" error occurs.

This the error:
"coldfusion.runtime.StructWrapper; local class incompatible: stream classdesc serialVersionUID = -4892312741747265515, local class serialVersionUID = 8172165491099780145 "

Did someone found a solution for this problem?
# Posted By Tiki Howpu | 9/29/11 5:44 AM
Jason Delmore's Gravatar I believe serialVersionUID is (or at least can be) set on a per class basis. If the serialVersionUID has been updated, it means that the developers intentionally marked that class as no longer compatible with older versions of that class. In this case, I'm guessing they made changes to the structWrapper class between 8 and 9. If it's a struct you are trying to serialize, you may want to consider JSON.

As for taking a serialized object across versions, if the objects versioning says it is not backwards compatible, I can't say I know how to tell it otherwise.
# Posted By Jason Delmore | 9/29/11 10:50 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.9. Contact Blog Owner