Reputation: 1125
I have ColdFusion 9.0.1 with the latest hotfix (4). I need ColdFusion to return all JSON data with quotes around them (as strings). I have the following problem:
<cfset test = StructNew()>
<cfset test.name = "1234.100">
<cfoutput>#SerializeJSON(test)#</cfoutput>
The text that is outputted is:
{"name":1234.100}
Every javascript JSON parser converts that to 1234.1 and is not keeping the trailing 0's. I either need ColdFusion to output as string or a javascript parser to keep the trailing 0's. Any ideas?
This is a simplified example. I am grabbing this data from a database.
Upvotes: 17
Views: 7666
Reputation: 1541
If you have an array of variables that you want to be treated as strings (such as a postal tracking numbers "9449311899561067336896") you may run into an issue where ColdFusion thinks the strings look like numbers. ColdFusion may then try to convert the strings to integers, but if they are too long for an integer, an error may result. This could happen when the strings originated from an Array inside of Deserialized JSON.
You may think you could use the strings like this:
<cfset trackIdXml = "" />
<!--- Loop through all tracking numbers and build the XML --->
<cfloop array="#trackingNumsArray#" index="i">
<cfset trackIdXml &= "<TrackID ID=""" />
<cfset trackIdXml &= #trackingNumsArray[i]# />
<cfset trackIdXml &= """/>" />
</cfloop>
But it will result in an error such as Cannot convert the value 9.449311899561067E21 to an integer because it cannot fit inside an integer.
Instead you can use cfscript and java.lang.StringBuffer
:
<cfscript>
//This variable will store the XML that is used in the API request to list each tracking number
//We must tell ColdFusion that this is a string buffer, and use .append(). Why?
//ColdFusion will try to convert the tracking number to a integer if we do not explicitly tell it
//to treat it as a string.
trackIdXml = createObject("java", "java.lang.StringBuffer").init();
for (trackingNum in trackingNumsArray) {
trackIdXml.append('<TrackID ID="');
trackIdXml.append(#trackingNum#);
trackIdXml.append('"/>');
}
</cfscript>
The trackIdXml
variable was created inside of the cfscript tags, but can still be used like other Coldfusion variables, for example in a cfreturn <cfreturn #trackIdXml# />
Here is a full real-world example that requires integer-like strings to be kept as strings. This is a function that accepts an Array of USPS tracking numbers, and returns the package status response from the USPS's API:
<cfcomponent>
<cffunction name="uspsLookup" access="remote" returntype="string" returnformat="plain" output="yes">
<cfargument name="trackingNums" type="string" required="yes" />
<cfset trackingNumsArray = DeserializeJSON(trackingNums, true) />
<cfscript>
trackIdXml = createObject("java", "java.lang.StringBuffer").init();
for (trackingNum in trackingNumsArray) {
trackIdXml.append('<TrackID ID="');
trackIdXml.append(#trackingNum#);
trackIdXml.append('"/>');
}
</cfscript>
<cfset userid = "XXXXXXXXXXXX" />
<cfhttp
method="GET"
url='http://production.shippingapis.com/ShippingAPI.dll?API=TrackV2&XML=<TrackRequest USERID="#userid#">#trackIdXml#</TrackRequest>'>
</cfhttp>
<cfif #cfhttp.Statuscode# IS "200 OK" >
<cfreturn "#cfhttp.Filecontent#">
<cfelse>
<cfreturn "error||#cfhttp.Statuscode#">
</cfif>
</cffunction>
</cfcomponent>
Upvotes: 1
Reputation: 331
I know this issue is old, but as a new CF developer, I came across this same issue, and while I used the 'string Hack' above successfully, finally I found a more suitable resolution from the Cold Fusion docs for serializeJSON.
'Adobe ColdFusion (2016 release) Update 2 enables you to specify the datatype information for keys in a struct. This is known as metadata.'
<cfscript>
example = structnew();
example.firstname = "Yes";
example.lastname = "Man";
writeoutput("<b>After serialization</b>:");
// change the JSON key firstname to fname
metadata = {firstname: {type:"string",name:"fname"}};
example.setMetadata(metadata);
writeoutput(SerializeJSON(example));
</cfscript>
While the example shows modifying the metadata for the string 'Yes', to stay a string, and not be converted to a boolean, it works just as well for turning numbers into strings for JSON serialization.
Upvotes: 14
Reputation: 1125
If you don't want to use a kludge, you can use a third party library that encodes JSON correctly. I used JSONUtil from http://jsonutil.riaforge.org/. I am using ColdFusion 9 so I don't know if the more recent versions of ColdFusion have fixed some of the encoding abnormalities.
Upvotes: 1
Reputation: 17
Just add a simple whitespace at the beginning of your number. I tried doing it at the end but it doesn't work.
<cfset test = StructNew()>
<cfset test.name = " 1234.100">
<cfoutput>#SerializeJSON(test)#</cfoutput>
The output will be
{"name":" 1234.100"}
Upvotes: -1
Reputation: 19941
Here's a solution - albeit a very hacky, inelegant solution...
Your setup:
var test = {
name = "1234.100"
};
Adding some obvious string to the front forces the value to become a string when it is converted to JSON. Then we get rid of this ugly string.
var thisIsSuchAHorribleHack = "(!@$!@$)";
test.name = thisIsSuchAHorribleHack & test.name;
var serializedTest = SerializeJSON(test);
serializedTest = Replace(serializedTest, thisIsSuchAHorribleHack, "", "ALL");
writeOutput(serializedTest);
Upvotes: 9