JustM
JustM

Reputation: 45

How to implement a Newtonsoft JSON converter that will serialize/deserialize a complex type into a simple type

I am looking to implement https://github.com/HeadspringLabs/Enumeration. Currently when I try to serialize/deserialize an Enumeration it serializes it like a complex object. For example, the object Color:

public class Color : Enumeration<Color, int>
{
    public static readonly Color Red = new Color(1, "Red");
    public static readonly Color Blue = new Color(2, "Blue");
    public static readonly Color Green = new Color(3, "Green");

    private Color(int value, string displayName) : base(value, displayName) { }
}

will serialize to

{ 
    "_value": 2, 
    "_displayName": "Something" 
}

In a complex object like this:

public class OtherClass
{
    public Color Color {get; set;}
    public string Description {get; set;}
}

it will serialize like this:

{
    "Description" : "Other Description",
    "Color" :
    { 
        "_value": 2, 
        "_displayName": "Something" 
    }
}

Is there any way to make json convert serialize the complex object like this:

{
    "Description" : "Other Description",
    "Color" : 2
}

I can create the correct Color object just from the value by using the method FromValue in the Enumeration class. I just can't seem to make json convert take the property value as the "value" for the Color object.

In what way can I write the WriteJson and Create methods of the converter in order to achieve that?

public class EnumerationConverter : JsonCreationConverter<IEnumeration>
        {
            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
            {
            }

            protected override IEnumeration Create(Type objectType, JObject jObject)
            {
            }
        }

Upvotes: 1

Views: 1788

Answers (1)

Brian Rogers
Brian Rogers

Reputation: 129827

You can make a generic converter for your Headspring.Enumeration<T, int>-derived class(es) like this:

class EnumerationConverter<T> : JsonConverter where T : Headspring.Enumeration<T, int>
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(T);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        int val = Convert.ToInt32(reader.Value);
        return Headspring.Enumeration<T, int>.FromValue(val);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var enumVal = (Headspring.Enumeration<T, int>)value;
        writer.WriteValue(enumVal.Value);
    }
}

To use the converter, add a [JsonConverter] attribute to your enum class(es) like this:

[JsonConverter(typeof(EnumerationConverter<Color>))]
public class Color : Headspring.Enumeration<Color, int>
{
    public static readonly Color Red = new Color(1, "Red");
    public static readonly Color Blue = new Color(2, "Blue");
    public static readonly Color Green = new Color(3, "Green");

    private Color(int value, string displayName) : base(value, displayName) { }
}

Here's a round-trip demo: https://dotnetfiddle.net/CZsQab

Upvotes: 3

Related Questions