Override Default Primitive Type Handling During Deserialization

Mar 29, 2012 at 4:21 PM

Is there any facility in json.net to override how the json deserialization process handles the deserialization of primitive typesSpecifically, I am having trouble with the fact that json.net deserializes int to long and decimals to doubles. Now I know the original type information gets lost when serialized but for the scope of my application I would really enjoy the ability to set Integer tokens always deseralized to int and Float tokens deserialized to decimal.

In my app I am passing json.net serialized C# dictionaries, object arrays, and DataTables to which contain only primitive types including decimals and DateTimes. Nowhere in the app are long or doubles used, so I think I'm safe in simply forcing the json tokens to the types I desire.

I've tried hacking around with implementing my own JsonConverters, but I haven't had any luck. The closest I've come to a solution is extending and implementing my own JsonTextReader and overriding SetToken(JsonToken newToken, object value) and changing the type there. Unfotunatly the virtual keyword was removed from JsonReader.SetToken in 4.0.6, so this only works on version 4.0.5 and it doesn't work with DataTables due to the way the DataTableConverter class works (which resets the types back to long/double after the SetToken method is called).

Thanks.

Aug 17, 2012 at 4:09 PM

+1 for this request. I avoid floats and doubles in APIs in all cases, preferring decimals instead. Looking at the JsonTextReader implementation I don't see any way to override this behavior, so I think it would require a code change to Json.NET.

Aug 17, 2012 at 4:43 PM
Edited Aug 17, 2012 at 4:45 PM

I ended up implementing this on my own by creating my own JsonConverter's for DataSets and DataTables. Created my own version of https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Converters/DataTableConverter.cs

but I changed the GetColumnDataType method to the following:

        private static Type GetColumnDataType(JsonToken tokenType)
        {
            switch (tokenType)
            {
                case JsonToken.Integer:
                    return typeof(int);         // Return int instead of long
                case JsonToken.Float:
                    return typeof(decimal);     // Return decimal instead of double
                case JsonToken.String:
                case JsonToken.Null:
                case JsonToken.Undefined:
                    return typeof(string);
                case JsonToken.Boolean:
                    return typeof(bool);
                case JsonToken.Date:
                    return typeof(DateTime);
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }