CSharp: JSON values with decimal point are generated as `long` properties, should be `double`/`decimal`
SivkovSavely opened this issue · 0 comments
Minimal reproducible example:
JSON:
{
"test": 123.0
}
Resulting CSharp:
// <auto-generated />
//
// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
//
// using QuickType;
//
// var welcome = Welcome.FromJson(jsonString);
namespace QuickType
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class Welcome
{
[JsonProperty("test")]
public long Test { get; set; }
}
public partial class Welcome
{
public static Welcome FromJson(string json) => JsonConvert.DeserializeObject<Welcome>(json, QuickType.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this Welcome self) => JsonConvert.SerializeObject(self, QuickType.Converter.Settings);
}
internal static class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters =
{
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
}
}
As you can see, QuickType results in type long
, even though there is a .0
in the JSON.
Yes, if I change it to .1
, the resulting type will be double
or decimal
, depending on the settings.
But I want QuickType to detect that I have .0
in the value, and generate a decimal number type, not integer.
Current behavior:
- If a number key in the object is
123.0
(i.e. there is a decimal part, but it's zero), the resulting type islong
. - If a number key in the object is
123.1
(i.e. there is a decimal part, and it's not zero), the resulting type isdouble
ordecimal
. - If a number key in the object is
123
(i.e. there is no decimal part), the resulting type islong
.
Expected/desirable behavior:
- If a number key in the object is
123.0
(i.e. there is a decimal part, but it's zero), the resulting type isdouble
ordecimal
. - If a number key in the object is
123.1
(i.e. there is a decimal part, and it's not zero), the resulting type isdouble
ordecimal
. - If a number key in the object is
123
(i.e. there is no decimal part), the resulting type islong
.
Why?
Because otherwise C# throws an error like this:
Unhandled exception. System.Text.Json.JsonException: The JSON value could not be converted to System.Int64. Path: $.payload.0.payload[0].loyalty[0].amount | LineNumber: 50 | BytePositionInLine: 43.
---> System.FormatException: Either the JSON value is not in a supported format, or is out of bounds for an Int64.
at System.Text.Json.ThrowHelper.ThrowFormatException(NumericType numericType)
at System.Text.Json.Utf8JsonReader.GetInt64()
at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
at System.Text.Json.Serialization.JsonCollectionConverter`2.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, TCollection& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
at System.Text.Json.Serialization.JsonCollectionConverter`2.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, TCollection& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
at System.Text.Json.Serialization.JsonDictionaryConverter`3.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, TDictionary& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 utf8Json, JsonTypeInfo`1 jsonTypeInfo, Nullable`1 actualByteCount)
at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 json, JsonTypeInfo`1 jsonTypeInfo)
at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options)
at AAA.BBB.AccountsRoot.FromJson(String json) in C:\Users\...\RiderProjects\AAA\AAA\BBB\Commons.cs:line 451
at my code that executes AccountsRoot.FromJson
the stack trace above is from my actual JSON that I needed to convert to CSharp classes in QuickType. but the point still stands - the System.Text.Json serializer cannot deserialize 123.0
into a long, therefore it should be a decimal or a double.
This change can become a default behavior, or be toggleable with a checkbox in the options, doesn't matter.
The only workaround I see now is to replace /(\d+)\.0+\b/
(or something) with $1.001
or something, e.g. turn 123.0
into 123.001
to force QuickType to turn numbers with .0
into decimals, while keeping integer values (e.g. 123
) intact.