JSON Files As Temporary File Storage In ColdFusion Applications
Posted January 18, 2010 at 9:29 AM
I love databases; but, if I'm writing a small application or proof of concept, often times, I don't want to have to go through the bother of creating a new database and its accompanying Data Source Name (DSN). In cases like this, I'll typically use flat files to persist simple data between application instantiations. In the past, I would have used XML and WDDX to perform the serialization and deserialization of data; but, with ColdFusion 8, I have switched over to JSON (Javascript Object Notation) as my persisted data format of choice.
ColdFusion 8 gave us some great new functionality. Not only did it give us Function-based ways to read and write files - fileRead() and fileWrite() - it also gave us functions for serializing and deserializing JSON data. With these two sets of functions in hand, I quickly found JSON to be a super easy way to quickly write ColdFusion objects to disk and then read them back in.
To demonstrate, take a look at this sample code:
Launch code in new window » Download code as text file »
- <!---
- Get the full file path to the directory in which we are
- storing our serialized JSON data files.
- --->
- <cfset dataDirectory = getDirectoryFromPath(
- getCurrentTemplatePath()
- ) />
-
- <!--- Create a basic ColdFusion object. --->
- <cfset girl = {
- name = "Joanna",
- hair = "Brunette",
- bestAttributes = [
- "Smile",
- "Legs"
- ]
- } />
-
-
- <!---
- Serialize the ColdFusion data object into a JSON string
- and write it to disk.
- --->
- <cfset fileWrite(
- "#dataDirectory#data.json",
- serializeJSON( girl )
- ) />
-
- <!---
- Read in serialized JSON string a deserialized it back into
- a ColdFusion data object.
- --->
- <cfset girlFromJSON = deserializeJSON(
- fileRead( "#dataDirectory#data.json" )
- ) />
-
-
- <!--- Output the ColdFusion data object created JSON. --->
- <cfdump
- var="#girlFromJSON#"
- label="JSON to ColdFusion"
- />
Here, I'm using serializeJSON() and fileWrite() to store the ColdFusion data to a flat file; then, I'm using fileRead() and deserializeJSON() to turn a flat file back into a ColdFusion object. Like I said - super easy! And, when we run the above code, we get the following output:
| | | | | |
| | ![]() | | ||
| | | |
As a comparison to the JSON approach, I figured I'd also show you my older, XML / WDDX approach:
Launch code in new window » Download code as text file »
- <!---
- Get the full file path to the directory in which we are
- storing our serialized JSON data files.
- --->
- <cfset dataDirectory = getDirectoryFromPath(
- getCurrentTemplatePath()
- ) />
-
- <!--- Create a basic ColdFusion object. --->
- <cfset girl = {
- name = "Joanna",
- hair = "Brunette",
- bestAttributes = [
- "Smile",
- "Legs"
- ]
- } />
-
-
- <!--- Serailize the ColdFusion object into a WDDX string. --->
- <cfwddx
- action="cfml2wddx"
- input="#girl#"
- output="girlWDDX"
- />
-
- <!--- Write the WDDX data to disk. --->
- <cfset fileWrite(
- "#dataDirectory#data.xml",
- girlWDDX
- ) />
-
- <!---
- Read in serialized WDDX string a deserialized it back into
- a ColdFusion data object.
- --->
- <cfwddx
- action="wddx2cfml"
- input="#fileRead( '#dataDirectory#data.xml' )#"
- output="girlFromWDDX"
- />
-
- <!--- Output the ColdFusion data object created JSON. --->
- <cfdump
- var="#girlFromWDDX#"
- label="WDDX to ColdFusion"
- />
This does the same thing, so I'm not going to bother showing the CFDump output - trust me, it does the same exact thing. The difference in the code is that we are using the CFWDDX tag to serialize and deserialize the ColdFusion data (to and from XML). Since there is no CFWDDX Function - it's only available in tag form - we have to add an extra step to perform the serialization (the file read and WDDX deserialization can still be lumped into one step).
While the difference in invocation is not terribly huge, there's just something about the serializeJSON() and deserializeJSON() functions that I find very natural and easy to use. Plus, the data that gets generated as JSON is much smaller, and is, in my opinion, easier to understand and modify, than its WDDX data format counterpart.
JSON Data Format
{"BESTATTRIBUTES":["Smile","Legs"], "NAME":"Joanna", "HAIR":"Brunette"}
WDDX Data Format
<wddxPacket version='1.0'> <header/> <data> <struct> <var name='BESTATTRIBUTES'> <array length='2'> <string>Smile</string> <string>Legs</string> </array> </var> <var name='NAME'> <string>Joanna</string></var>< var name='HAIR'> <string>Brunette</string> </var> </struct> </data> </wddxPacket>
Maybe it's because I do so much work with AJAX and jQuery, but to me, the JSON data form is basically like reading English, where as I find the WDDX XML format requires actual mental parsing. Of course, I'm not here to sell you on JSON vs. XML (with or without WDDX). I'm just saying that ever since ColdFusion 8 adding JSON-based functions, JSON has become my flat file data storage format of choice; there's something about it that just feels really easy and natural to work with.
Download Code Snippet ZIP File
Post Comment | Ask Ben | Print Page
Newer Post
Maintaining ColdFusion Query Data Type Integrity Throughout The Serialization Life Cycle
Older Post
Project HUGE: Barbell Deadlifts - 365x5 With A Concentration On Form
Reader Comments
My only concern with this approach is how serializeJSON is typeless. If you have data you meant to be considered a string, serializeJSON will munge it. It can do things like changing 1 to 1.0. javacast() can help, but it's something you have to watch out for.
@Raymond,
Yeah, that's true. Going from typeless to typed, ColdFusion has to make some guess work. For example, if I added:
hotness: 9
... to my data struct, the JSON becomes:
HOTNESS: 9.0
... and the WDDX becomes:
<string>9</string>
So, the WDDX is more "accurate" based on the underlying ColdFusion data types (string based everything :)), but it's not necessarily accurate in the intent.
Of course, the "intent" of data storage is just that - data storage; as such, it's definitely a benefit that WDDX works better to that extent. However, I have to say that I have never personally run into an issue with JSON usage.... at least not yet :)
Ben, just one thing to note (you may already be aware of this), and it's something I ran into recently, for this type of scenario it may be important to use the second parameter of the serializeJSON and deserializeJSON functions, mainly because by default serializeJSON doesn't distinguish between a CF Structure and a CF Query. It serializes both as structures. Did a post about this http://bit.ly/8PRfba.
Interesting approach. With CF9 using ORM is great for stuff like this where you want to store data but don't want the hassle of dealing with databases.
@Donnie,
"The Don", good point. I forgot about that.
@Sam,
Exactly. I find it especially awesome with "proof of concept" type applications where just want to do a little experimentation.
Something else I'll add - and I blogged on this a few weeks back - JSON is a super quick way to log complex data to a log as well. Obviously you wouldn't want to cflog something big, but for quick and dirty logging it works great.
@Ben I am so going to do an avatar for that although it is not warranted at all! :)
You can in fact have typed deserialization with JSON, though I doubt ColdFusion will handle the magic for you the way it handles (de-)serialization for untyped object graphs.
Since JSON is just a JavaScript object literal, and in javascript an object has a type instead of is of type (i.e. it has a prototype), you could serialize an object graph with its type.
See http://tobyho.com/Typed_Deserialization_with_JSON
@Ray, @Donnie,
I found your comments though provoking fodder for a follow-up post:
One question:
That table output; is that some kind of default behaviour of CF or did you do some transformation on the data?
@Kristopher,
That is the way the CFDump tag outputs data.
That's beautiful! Where does it output to? What environment is that? I can only associate this to my TDD in Visual Studio when I'm looking at my output window...
@Kristopher,
It outputs directly to the current output buffer. The CFDump is a ColdFusion construct, so you'd have to be using ColdFusion.
My version of ColdFusion 8 chokes on the code for creating the ColdFusion object that you provide. Do you have a reference that I can explore for building objects the way you show? I see references to the cfobject tag but I can find nothing that looks like your code.
@Ward,
This code was built using ColdFusion 8. It's possible that you are missing one of the Updates / Patches. I think the nested implicit struct / array notation might be something that was done in one of the hot fixes.
Thanks for the quick response! I ran the code on my HostMySite account and it ran correctly. Now I need to update my Development ColdFusion installation and look deeper into the implicit struct / array notation. I see you covered it in an earlier blog entry.
BTW, I'm becoming a great fan of yours! I like the way you share your knowledge and following your routines is a great way to learn.
@Ward,
Oh great - glad we narrowed it down. And, thank you very much for the kind words :)




