3

Is it possible to convert decimals to integer when deserializing JSON using Newtonsoft.Json?

Suddenly our service is receiving JSON data containing decimal values where int types are expected, example: 18483.0.

As a result exceptions are thrown like "Newtonsoft.Json.JsonReaderException: Input string '18483.0' is not a valid integer."

Obviously this specific property is defined as integer, and I prefer not to change it to some decimal type, but to convert the input to int, and stripping the decimals (which are always .0 anyway).

George
  • 1,111
  • 3
  • 20
  • 38
  • Does this answer your question? [Custom deserializer only for some fields with json.NET](https://stackoverflow.com/questions/41510242/custom-deserializer-only-for-some-fields-with-json-net) – Crowcoder Sep 20 '22 at 14:14
  • Can you show an example of json you have received? – Serge Sep 20 '22 at 22:00

2 Answers2

4

You can have a custom generic JsonConverter like below :

public class CustomIntConverter : JsonConverter<int>
{
    public override void WriteJson(JsonWriter writer, int value, JsonSerializer serializer)
    {
        writer.WriteValue(value.ToString());
    }

    public override int ReadJson(JsonReader reader, Type objectType, int existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        return Convert.ToInt32(reader.Value);
    }
}

It tries to cast it to an integer if it fails then it casts it to a double and then to an int. You can use it like below :

var json = @"{""B"":42.0}";
var result = JsonConvert.DeserializeObject<A>(json, new CustomIntConverter());

Fiddle

Edit Applied @vernou's suggestion

Eldar
  • 9,781
  • 2
  • 10
  • 35
  • 1
    Using a safe cast `return reader.Value as int ?? ((int)(double)reader.Value);` might be a simpler method than blindly casting and catching an exception – Charlieface Sep 20 '22 at 14:26
  • I tested, it don't work. Json.Net return integer as `long`. Then `reader.Value` is a `long` and the cast to `int` or `double` fail. You can reproduce with `var json = @"{""B"":42}";`. – vernou Sep 20 '22 at 15:01
  • 1
    It's manage more case : `return Convert.ToInt32(reader.Value);` – vernou Sep 20 '22 at 15:01
  • @vernou indeed Json.Net has its default as `long` – Eldar Sep 20 '22 at 15:08
3

you can create a custom property converter

    var json = @"{ ""StringProperty"":""StringProperty"", ""IntProperty"":29.0}";

    var test = JsonConvert.DeserializeObject<Test>(json);

public class Test
{
    public string StringProperty { get; set; }

    [JsonConverter(typeof(DoubleToIntConverter))]
    public int IntProperty { get; set; }
}
    
public class DoubleToIntConverter : JsonConverter<int>
{
    public override void WriteJson(JsonWriter writer, int value, JsonSerializer serializer)
    {
        writer.WriteValue(value);
    }

        public override int ReadJson(JsonReader reader, Type objectType, int existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        return Convert.ToInt32( reader.Value);
    }
}
Serge
  • 40,935
  • 4
  • 18
  • 45