Infinity and JSON
Originally posted on the Agworld Developers Blog, hosted on Tumblr, on September 12, 2012.
It seems that many JSON parsers/generators aren’t idempotent when it comes to Infinity.
We had a problem recently where a floating point result from a .NET server was returned in a JSON string like this:
{"name": Infinity}
That ain’t valid JSON, according to RFC 4627. Here’s what happened when we try to parse it in Ruby:
>> require 'json'
=> true
>> result = '{"name": Infinity}'
=> "{\"name\": Infinity}"
>> JSON.parse(result)
JSON::ParserError: 216: unexpected token at ' Infinity}'
Luckily, we can work-around this problem as follows:
>> result.gsub!(/Infinity/, '1e1000')
=> "{\"name\": 1e1000}"
>> data = JSON.parse(result)
=> {"name"=>Infinity}
Great! So now we can do manipulations on the Ruby hash. But, later, if we render that Hash as JSON, then we’ll get problems.
>> data.to_json
JSON::GeneratorError: 775: Infinity not allowed in JSON
What happens on the JavaScript side? Much the same thing, it turns out:
> result = '{"name": Infinity}'
"{"name": Infinity}"
> JSON.parse(result)
SyntaxError: Unexpected token I
Even better, the solution is exactly the same:
> result = result.replace(/Infinity/g,"1e1000")
"{"name": 1e1000}"
> data = JSON.parse(result)
v Object
result: Infinity
> __proto__: Object
JavaScript does comply with RFC 4627, however, unlike the JSON libraries that we use in Ruby (and presumably unlike whatever the .NET service was doing):
> JSON.stringify(data)
"{"name":null}"
But the best solution, I think, would be to use the ‘1e1000’ hack to preserve the value of ‘Infinity’ from end-to-end.
This article was originally posted on the Agworld Developers Blog, hosted on Tumblr, on September 21, 2012, and is almost certainly out of date by now.