json net leading zeros (disable base-cast)

Json.Net can't correctly deserialize number with leading zeros.

For example { "number":010 } recognized as 8 (because 010 in 8 base equal 8 in 10 base)

if look at JsonTextReader.ParseNumber() you can see

long value2 = text2.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(text2, 16) : Convert.ToInt64(text2, 8);

How it possible disable base-cast? Maybe possible replace JsonTextReader?


Since leading zeros are disallowed by the the JSON standard, it would seem Newtonsoft decided to implement parsing of JavaScript-style octal numbers as an extension to the standard, see Json.NET 3.5 Release 7 – Biggest Release Ever Edition. This behavior is currently hardcoded into JsonTextReader.ParseReadNumber(ReadType readType, char firstChar, int initialPosition) with no option to force strict conformance to the standard (i.e. throw an exception on a leading zero), as is stated in:

  • Override Json deserializing a number with a leading zero as a decimal and not an octal value.
  • Int parsing not working properly #1057.
  • Deserializing a number with a leading zero #924.
  • Support "strict mode" for RFC7159 parsing #646.

As a workaround, you could use JavaScriptSerializer to parse to an intermediate dynamic object, then re-serialize that to an intermediate JToken, then deserialize that JToken to your final class:

var json = @"{ ""number"":010 }";

var root = JToken.FromObject(new JavaScriptSerializer().DeserializeObject(json)).ToObject<RootObject>();

if (root.Number != 10)
{
    throw new InvalidOperationException();
}

Using

class RootObject
{
    public int Number { get; set; }
}

You could also re-serialize to an intermediate JSON string, but re-serializing to an intermediate JToken should be more efficient for larger objects.

(Switching to DataContractJsonSerializer or JavaScriptSerializer are also options if you do not need the full functionality of Json.NET, since both will silently parse an integer with a leading zero in base 10.)

Another option would be to fork your own version of JsonTextReader and all associated utilities, and fix the logic of JsonTextReader.ParseReadNumber() to throw a JsonReaderException when nonBase10 is true. Unfortunately, forking your own JsonTextReader may require substantial ongoing maintenance, since you will also need to fork any and all Newtonsoft utilities used by the reader (there are many) and update them to any breaking changes in the original library. You could also vote up or comment on enhancement request #646 requesting strict integer parsing.

Why did Newtonsoft implement parsing of numbers in octal syntax? My speculation is that they added this functionality to handle numbers formatted in the JavaScript syntax for integer literals:

Integers

Integers can be expressed in decimal (base 10), hexadecimal (base 16), octal (base 8) and binary (base 2).

  • Decimal integer literal consists of a sequence of digits without a leading 0 (zero).
  • Leading 0 (zero) on an integer literal, or leading 0o (or 0O) indicates it is in octal. Octal integers can include only the digits 0-7.
  • Leading 0x (or 0X) indicates hexadecimal. Hexadecimal integers can include digits (0-9) and the letters a-f and A-F.

  • Leading 0b (or 0B) indicates binary. Binary integers can include digits only 0 and 1.