Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
828 views
in Technique[技术] by (71.8m points)

c# - 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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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:

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...