Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom JsonConverter that can convert decimal.MinValue to empty string and back

I need to create a custom JSON.NET converter for a legacy system that flags null decimal values with...

var nulldec = decimal.MinValue;

(This was created before nullable types were introduced, and to change how this works will be a ton of work.)

When these min-values are serialized to JSON they need to be serialized as an empty string. When they are deserialized, if the value is empty string, it needs to convert to decimal.MinValue.

Here is what I have so far (yes, not much). I think this is a simple conversion, but I am not seeing any articles that point me to how to work this for my situation nor any documentation on how to create custom converters. Can someone help please?

public class DecimalJsonConverter : JsonConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, 
                                    object existingValue, JsonSerializer serializer)
    {
    }
    public override void WriteJson(JsonWriter writer, object value, 
                                   JsonSerializer serializer)
    {
    }
    public override bool CanConvert(Type objectType)
    { 
        return typeof(System.Decimal).IsAssignableFrom(objectType); 
    }
}
like image 602
John Livermore Avatar asked Mar 17 '23 20:03

John Livermore


1 Answers

The following converter implementation should give you what you want:

public class DecimalJsonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(decimal));
    }

    public override object ReadJson(JsonReader reader, Type objectType, 
                                    object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.String)
        {
            if ((string)reader.Value == string.Empty)
            {
                return decimal.MinValue;
            }
        }
        else if (reader.TokenType == JsonToken.Float || 
                 reader.TokenType == JsonToken.Integer)
        {
            return Convert.ToDecimal(reader.Value);
        }

        throw new JsonSerializationException("Unexpected token type: " +
                                             reader.TokenType.ToString());
    }

    public override void WriteJson(JsonWriter writer, object value, 
                                   JsonSerializer serializer)
    {
        decimal dec = (decimal)value;
        if (dec == decimal.MinValue)
        {
            writer.WriteValue(string.Empty);
        }
        else
        {
            writer.WriteValue(dec);
        }
    }
}

Here is a round-trip demo:

class Program
{
    static void Main(string[] args)
    {
        string json = @"
        {
            ""MinValueAsString"" : """",
            ""ARealDecimal"" : 3.14159,
            ""AnInteger"" : 42
        }";

        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.Converters.Add(new DecimalJsonConverter());
        settings.Formatting = Formatting.Indented;

        Foo foo = JsonConvert.DeserializeObject<Foo>(json, settings);

        Console.WriteLine("MinValueAsString: " + foo.MinValueAsString);
        Console.WriteLine("ARealDecimal: " + foo.ARealDecimal);
        Console.WriteLine("AnInteger: " + foo.AnInteger);
        Console.WriteLine();

        json = JsonConvert.SerializeObject(foo, settings);
        Console.WriteLine(json);
    }

    class Foo
    {
        public decimal MinValueAsString { get; set; }
        public decimal ARealDecimal { get; set; }
        public decimal AnInteger { get; set; }
    }
}

Output:

MinValueAsString: -79228162514264337593543950335
ARealDecimal: 3.14159
AnInteger: 42

{
  "MinValueAsString": "",
  "ARealDecimal": 3.14159,
  "AnInteger": 42.0
}

Fiddle: https://dotnetfiddle.net/dip85r

like image 161
Brian Rogers Avatar answered Apr 07 '23 19:04

Brian Rogers