Thursday 4 July 2013

Right... so JSON is being a pain in the arse again

G'day:
You might have seen my Twitter status update earlier today, which went kinda like this:

#ColdFusion.... JSON... AGAIN... AAAAAAAAAAAARRRRRRRRRRRRRGGGGGGGGGGGHHHHHHHH!!!!!!!

The degree to which ColdFusion can't get JSON right just beggars belief.

Today we discovered CF9 (and confirmed on CF10) cannot even handle bloody strings correctly.

Sorry to be all shouty and stuff, but this is just getting beyond a joke.

We don't only use ColdFusion at work, we also have a bunch of C#-written DotNet-based applications providing web services for the ColdFusion application. Today we had to pass a string to one of the .Net web services, and we simply could not coerce ColdFusion into serialising a value as a string.  "Huh?" you think, and quite rightly so. The thing is with this string... it just happens to be a sequence of digits. It's not a number, it's not a numeric value. It's a string that just happens to comprise entirely of digits.

So... try to tell ColdFusion that. Go on.

Here's some code.

intValue    = 123;
strValue    = "#intValue#";

javaCastVariable = javaCast("String", intValue);
data = {
    hardCodedString        = "123",
    hardCodedInt        = 123,
    intVariable         = intValue,
    intVariableQuoted    = """#intValue#""",
    toString            = toString(intValue),
    javaCast            = javaCast("String", intValue),
    newVariable            = strValue,
    javaCastVariable    = javaCastVariable,
    javaString            = createObject("java", "java.lang.String").init(intValue)
};
json = serializeJson(data);

writeDump([data,json]);

There's some control values in there, but there's also all the ways I could think of telling ColdFusion that the value is a string. No. No. To ColdFusion they're all bloody numbers:

array
1
struct
HARDCODEDINT123
HARDCODEDSTRING123
INTVARIABLE123
INTVARIABLEQUOTED"123"
JAVACAST123
JAVACASTVARIABLE123
JAVASTRING123
NEWVARIABLE123
TOSTRING123
2{
"JAVACAST":123,
"JAVACASTVARIABLE":123,
"INTVARIABLEQUOTED":"\"123\"",
"JAVASTRING":123,
"INTVARIABLE":123,
"HARDCODEDSTRING":123,
"HARDCODEDINT":123,
"NEWVARIABLE":123,
"TOSTRING":123
}

Every single bloody one of them has been converted into a number. Why, Adobe? Just why? I can understand just the basic ones in which I use an actual number, or even the ones where I used quoted numbers... CF has a guess at the type, and decides "number". Now it should not do that when the thing is quoted, irrespective of its contents, because clearly a quoted value is a string. What's even more a string is the result of a call to javaCast("string"), and especially an actual Java string object. I could also understand if I passed a string-containing-digits to a function which expected a numeric for ColdFusion to be kindly enough to cast the string to a numeric. CF is loosely-typed and this is what it should be doing. However at no stage of the "putting the value into a struct" or "serialising the struct" is there any need to mess with the values going into or already in the struct. There's no need to change the data type.

I hasten to add it's not the "putting it into the struct" bit that's screwing things up, because if I do this:

<cfoutput>#serializeJson("123")#</cfoutput>

I get this:

123

Wrong.

One might think or claim "oh yeah, but ColdFusion has no way of knowing whether it's a string or a numeric, so it's making its best guess". OK, well explain how Railo can do it just fine then?

Array
1
Struct
HARDCODEDINT
number123
HARDCODEDSTRING
string123
INTVARIABLE
number123
INTVARIABLEQUOTED
string"123"
JAVACAST
string123
JAVACASTVARIABLE
string123
JAVASTRING
string123
NEWVARIABLE
number123
TOSTRING
string123
2
string{
"INTVARIABLEQUOTED":"\"123\"",
"HARDCODEDINT":123,
"INTVARIABLE":123,
"HARDCODEDSTRING":"123",
"JAVACAST":"123",
"JAVACASTVARIABLE":"123",
"TOSTRING":"123",
"JAVASTRING":"123",
"NEWVARIABLE":123
}

And for the second code example, it returns:

"123"

Adobe have fixed a lot of the JSON bugs that arose in CF9 for CF10, but this one is still broken in CF10.

I shall raise a ticket... .

Do you know what's worst about this? Having to explain to the very bemused .Net guys how - no - we cannot even pass a string to you properly. Sorry.

--
Adam