ColdFusion, JSON, and Booleans
Posted by
Brad Wood
Sep 10, 2008 08:17:00 UTC
Last night I found myself wrestling with the behavior of ColdFusion's JSON serializing where the strings "yes" and "no" are converted to a Boolean and come out the other side as "true" and "false". This happens when variables are passed through SerializeJSON(), or a CFC is called with returnFormat="json". Nathan Mische pointed out not too long ago that 1 and 0 are NOT converted to Booleans, which is interesting.
I have a feeling the logic goes something like this:
[code]If string can be converted to a number Treat it as a number Else if it can be converted to a Boolean Treat it as a Boolean Else Treat it as a string [/code]1's and 0's probably get picked off early that way. As annoying as it is though, I'm not sure what the better solution would be. Unfortunately, in a loosely typed language the server has to make guesses for you that can be kind of un-forgiving when you translate them to a strictly typed language. In my case, I was passing back a result set to be bound to a cfgrid, so I didn't really have much control of how it displayed once it left the server. I needed it to come back from the server in the correct format. My solution was to add a space before or after each word such as "yes " and "no ". It's not quite optimal, but it works. The results were left as string and made it safely back to the browser. As far as a work-around from Adobe, I had originally thought of adding an additional setting called strictBooleanParsing or something, but what worked for one person would probably never work for someone else. In the end, it might have been best for them to ONLY accept "true" and "false" as Booleans. I don't think that would be too much to ask programmers to do. I mean, it's nice that you can be all loosey-goosey inside of ColdFusion with your data types, but I wouldn't expect that same kind of freedom when I want to convert my data to a less forgiving format. This might never be changed though given the backwards compatibility issue. There is probably code out there now that depends on "yes" and "no" turning Boolean. What would your solution be?
Tags: ColdFusion, JavaScript
Ben Nadel
I know what you are saying. I have found through practice to just always use true and false for booleans. Frankly, I am surprised that SerializeJSON() handles those so well! I assumed they would get passed back as strings as well.
Brad Wood
@Ben: Yeah, NULL values in query results threw me for a loop. I was getting "null" output on the page so I whipped up a quick JavaScript ternary checking for value == 'null' but it didn't work. Turns out, they were honest to goodness JavaScript nulls, not just the string. I had to do value == null.
It's kind of cool actually that nulls are preserved. However, I am used to ColdFusion's treatments, where they become empty strings.
Nathan Mische
The problem with how CF handles Booleans in JSON is that, while "yes" is the same thing as true in CF, it is not in JavaScript, and JSON is JavaScript. This can lead to data loss. Say you have the string "yes", you serialize it as JSON and it becomes true. Now I don't know what the original value was. Was true, “trueâ€, or "yes"? I have no way of knowing.
If I need to handle “yes†as true in the consuming client I should do that there. CF should not make this assumption for me. (If the consumer is CF then it will handle "yes" as a boolean, just like it always does.) In my mind this is a bug and I’ve reported it as such.
William from Lagos
ever tried JavaCast() function? i remember something similar that the ColdFusion Jedi was trying to solve.
Ben Nadel
@Brad,
That is pretty interesting. I am surprised that it carries the null value over. Very cool.
Brad Wood
@william: Using JavaCast() doesn't do anything:
cfset test = javacast("string","yes")> #serializejson(javacast("string",test)) That code still returns "true"
JavaCast wouldn't even be possible in a lot of cases. Consider the following Ajax webservice:
cffunction name="getStuff" access="remote" returnformat="json"> cfquery name="qryStuff"> SELECT * FROM stuff /cfquery cfreturn qryStuff> /cffunction>
You wouldn't even have a chance to cast anything.
Nathan Mische
So I was doing some more work with this tonight and found that Booleans are actually stored as strings in CF. <cfset stringBoolean = "true" /> and <cfset booleanBoolean = true /> both give you Java strings. This means that there is probably no way for the SerializeJSON function to distinguish between "true" and true. I still think "yes" and "no" should be serialized as strings. (As a side note, Thomas Messier's cfjson component does encode "yes" and "no" as strings.)