G'day:
This might actually be a manifestation of the same issue I wrote about a while back: "
Right... so JSON is being a pain in the arse again". And I didn't spot this one myself - I've given up on using JSON in ColdFusion as it's just too unstable - but read about it on a thread on CF-TALK (it's not in the archive yet, so I cannae link to it).
Anyway, this time the issue is with ColdFusion and "strings that look like numbers" again, but a different slant on it. Consider this code:
number = .0006;
struct = {number=number};
json = serializeJSON(struct);
writeDump([
{number=number},
{"struct.number"=struct.number},
{struct=struct},
{json=json}
]);
On ColdFusion (9, and apparently 10 too, going from the thread I can't link you to...), the output is this:
array |
1 |
|
2 |
struct |
struct.number | .0006 |
|
3 |
|
4 |
struct |
JSON | {"NUMBER":6.0E-4} |
|
Nice. Thanks for that, ColdFusion. Just in case yer really going "wah??" there, that's scientific notation for 0.0006. So, ColdFusion... which part of "turn this into JSON" did you interpret as "turn this into JSON and any numbers with more then three decimal place? Scientific notation please". Just to demonstrate that this is not "just one of those things", here's the output in Railo:
All good.
I extended this code to try to work out WTF is going on:
number = .0006;
forcedNumber = number * 1;
forcedStringJava = number.toString();
forcedStringCfml = toString(number);
double = createObject("java", "java.lang.Double").init(0.0006);
float = createObject("java", "java.lang.Float").init(0.0006);
string = ".0006";
struct = {number=number,forcedNumber=forcedNumber,forcedStringJava=forcedStringJava,forcedStringCfml=forcedStringCfml,double=double,float=float,string=string};
json = serializeJSON(struct);
writeDump([
{"struct.number"=struct.number},
{"struct.forcedNumber"=struct.forcedNumber},
{"struct.forcedStringJava"=struct.forcedStringJava},
{"struct.forcedStringCfml"=struct.forcedStringCfml},
{"struct.double"=struct.double},
{"struct.float"=struct.float},
{"struct.string"=struct.string},
{struct=struct},
{json=json}
]);
And the output didn't really have me any the wiser:
array |
1 |
struct |
struct.number | .0006 |
|
2 |
struct |
struct.forcedNumber | 0.0006 |
|
3 |
struct |
struct.forcedStringJava | .0006 |
|
4 |
struct |
struct.forcedStringCfml | .0006 |
|
5 |
struct |
struct.double | 0.0006 |
|
6 |
struct |
struct.float | 6.0E-4 |
|
7 |
struct |
struct.string | .0006 |
|
8 |
struct |
STRUCT |
struct |
DOUBLE | 0.0006 |
FLOAT | 6.0E-4 |
FORCEDNUMBER | 0.0006 |
FORCEDSTRINGCFML | .0006 |
FORCEDSTRINGJAVA | .0006 |
NUMBER | .0006 |
STRING | .0006 |
|
|
9 |
struct |
JSON | {
"DOUBLE":6.0E-4,
"FORCEDSTRINGJAVA":6.0E-4,
"FLOAT":6.0E-4,
"FORCEDSTRINGCFML":6.0E-4,
"FORCEDNUMBER":6.0E-4,
"STRING":6.0E-4,
"NUMBER":6.0E-4
} |
|
Railo had an interesting quirk:
Array |
1 |
|
2 |
|
3 |
Struct |
struct.forcedNumber |
|
|
4 |
Struct |
struct.forcedStringJava |
|
|
5 |
Struct |
struct.forcedStringCfml |
|
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
Struct |
STRUCT |
Struct |
DOUBLE |
|
FLOAT |
|
FORCEDNUMBER |
|
FORCEDSTRINGCFML |
|
FORCEDSTRINGJAVA |
|
NUMBER |
|
STRING |
|
|
|
11 |
Struct |
JSON |
string | {
"NUMBER":0.0006,
"FORCEDSTRINGCFML":"0.0006",
"STRING":".0006",
"FORCEDNUMBER":0.0006,
"FLOAT":0.000600000028,
"FORCEDSTRINGJAVA":"6.0E-4",
"DOUBLE":0.0006
} |
|
|
(Highlighting things in a Railo dump is a bit of a challenge ;-)
So that's some floating point inaccuracy at work which Railo lets us know about (good) but ColdFusion hides from us (bad).
Anyway, casting from a float to a string (outputting it necessitates it being cast to a string) results in the scientific notation, but this should be irrelevant as numerics in ColdFusion are all doubles, to the best of my knowledge? I presume this is a cock-up under the hood of their JSON serialiser. Someone on Twitter suggested the other day that Adobe would be better off using an external library rather than rolling their own - given they seem incapable of doing the job properly - might be a good idea. I agree. I could not agree more.
One interesting thing in all this. Check this out:
noLeadingZero = .0006;
withLeadingZero = 0.0006;
struct = {noLeadingZero=noLeadingZero, withLeadingZero=withLeadingZero};
json = serializeJSON(struct);
writeDump([
{struct=struct},
{json=json}
]);
array |
1 |
struct |
STRUCT |
struct |
NOLEADINGZERO | .0006 |
WITHLEADINGZERO | 0.0006 |
|
|
2 |
struct |
JSON | {"NOLEADINGZERO":6.0E-4,"WITHLEADINGZERO":0.0006} |
|
Right. So having the leading zero results in ColdFusion treating the value differently.
WTF, Adobe?
--
Adam