Earlier today I blogged about being aware of the differences between the way ColdBox and ColdFusion 8 handle variable names when serializing to JSON for remote calls (the original post name is much more elegant, I promise). Several questions arose as to the different ways variables can be created and how exactly each method would output, so I decided to put together this short test.

The test is rather simple. I create a structure with 9 keys: 3 using in-line declaration (<cfset struct = { key = value } />); 3 using dot-notation (<cfset struct.key = value />); 3 using array notation (<cfset struct[ "key" ] = value />). The difference between the 3 keys within each sub-set is that one key's name is all lowercase, another is all uppercase and the last uses camelCase.

Setting up the ColdFusion 8 test

After creating my new ColdBox application I setup a new file in the root of the project called cf-remote.cfc. It's pretty simple, so I'll just dump it right here.

cf-remote.cfc contents:

view plain print about
1<cfcomponent output="false">
2
3    <cffunction name="cf_testRemote" access="remote" returntype="struct">
4
5        <cfset var result = { mytest1="value1", MYTEST2="value2", myTest3="value3" } />
6
7        <cfset result.dottest1 = "dot1" />
8        <cfset result.DOTTEST2 = "dot2" />
9        <cfset result.dotTest3 = "dot3" />
10
11        <cfset result[ "arraytest1" ] = "array1" />
12        <cfset result[ "ARRAYTEST2" ] = "array2" />
13        <cfset result[ "arrayTest3" ] = "array3" />
14
15        <cfreturn result />
16
17    </cffunction>
18
19</cfcomponent>

We're setting up a simple service with a single method. We allow access from remote requests, and we declare we'll be returning a struct. The rest is just variable declaration to fit with our test and a return to caller.

Setting up the ColdBox test

Every remote call in a ColdBox app should pass by coldboxproxy.cfc. This proxy then turns around and asks ColdBox to execute the requested event. Our event looks pretty much the same as our CF8-only test, so here it is with details right after.

handlers/general.cfc contents:

view plain print about
1<cfcomponent name="general" extends="coldbox.system.eventhandler" output="false">
2
3    <cffunction name="init" access="public" returntype="general" output="false">
4        <cfargument name="controller" type="any">
5        <cfset super.init(arguments.controller)>
6        <!--- Any constructor code here --->
7        <cfreturn this>
8    </cffunction>
9
10    <cffunction name="cb_testRemote" access="public" returntype="void">
11        <cfargument name="event" type="any" required="true" />
12
13        <cfset var result = { mytest1="value1", MYTEST2="value2", myTest3="value3" } />
14
15        <cfset result.dottest1 = "dot1" />
16        <cfset result.DOTTEST2 = "dot2" />
17        <cfset result.dotTest3 = "dot3" />
18
19        <cfset result[ "arraytest1" ] = "array1" />
20        <cfset result[ "ARRAYTEST2" ] = "array2" />
21        <cfset result[ "arrayTest3" ] = "array3" />
22
23        <cfset event.renderData( type="json", data=result ) />
24
25    </cffunction>
26
27</cfcomponent>

There are two noticeable differences between the two tests. Even if we know that a ColdBox event will only be called by remote requests, we still set it's access to "public". The reason for this is that this method is actually called by the proxy, and not by the calling page. The other difference is the last line in the method. Rather than use <cfreturn />, we're using ColdBox's event.renderData() method. Events aren't made to return data explicitly, so even if we'd used <cfreturn /> the value wouldn't make it back to the caller. That's why we need to use this method from within ColdBox. What this does is serialize the variable provided into a JSON string so it can be returned to the calling page.

Viewing the results

All that's left now is executing our test. I told you this was a simple test, so here's the entirety of the client code.

The actual test:

view plain print about
1<script type="text/javascript" src="/scripts/lib/jquery-1.3.2.min.js"></script>
2
3<script type="text/javascript">
4<cfwddx action="cfml2js" input="#getSetting( 'AppMapping' )#" toplevelvariable="APPMAPPING" />
5$().ready( function () {
6
7    var path = "/" + APPMAPPING + "/";
8
9    $.getJSON( path + "coldboxproxy.cfc?method=process&event=general.cb_testRemote&returnFormat=plain", {}, function () {} );
10
11    $.getJSON( path + "cf-remote.cfc?method=cf_testRemote&returnFormat=json", {}, function () {} );
12
13});
14</script>

Using jQuery's $.getJSON() method we can easily ping both our methods and view the result. A quick rundown of what's happening in each AJAX call:

coldboxproxy.cfc
All my remote calls pass by coldboxproxy's process method. We then specify which event to execute (handler.action) and in which format to return it. We're using returnFormat="plain" here because we don't want ColdFusion to re-serialize the already JSON'ified string.
cf-remote.cfc
Pretty simple call. We ping cf-remote.cfc, and request the cf_testRemote method. We then ask ColdFusion to convert our result to a JSON string.

The results of all this

We didn't do all of this for nothing. Let's compare the results, as shown by Firebug.

ColdBox and event.renderData()

view plain print about
1{"dottest1":"dot1","dottest2":"dot2","dottest3":"dot3","arraytest1":"array1","arraytest2":"array2","arraytest3"
2:"array3","mytest1":"value1","mytest2":"value2","mytest3":"value3"}

ColdFusion 8 and returnFormat="json"

view plain print about
1{"DOTTEST1":"dot1","DOTTEST2":"dot2","DOTTEST3":"dot3","arraytest1":"array1","ARRAYTEST2":"array2","arrayTest3"
2:"array3","MYTEST1":"value1","MYTEST2":"value2","MYTEST3":"value3"}

Every single key, in ColdBox, is in lowercase. In ColdFusion 8, however, they're all uppercase... or are they? Notice the array_ tests. Keys named with array notation preserved their case. All other declarations were converted.

Personally, I like the fact that either solution converts to a specific case. Our JavaScript methods shouldn't have to care how a variable name was typed. It should be able to depend on the fact that key names are always lower- or upper- case. IMO, though, the fact that CF8 doesn't convert keys that were named through array notation to upper case makes it unreliable. Sure, it's always the same... As a CF developer, we know how we named our variables and we know what to expect. What happens, however, when another programmer is responsible for the JavaScript side? Does he constantly have to validate with the CF guy how he typed his variables? I may be nitpicking here, and it is getting kind of late, so I'll leave it to you. What do you think?