How to Deserialize Derived Objects in Json.NET

Imagine you need to process some JSON that looks like this:

{
	"vehicles": [
	{
		"type": "Car",
		"topSpeed": "180mph",
		"engine": "V8"
	},
	{
		"type": "Bike",
		"topSpeed": "20mph",
		"pedal": "Plastic"
	}]
}

Notice how the array contains similar objects, two vehicles. Each vehicle has a “type” property that identifies the specific type of vehicle. If we wanted to deserialize this into C# we could use the following classes:

public class Garage
{
    public List<Vehicle> Vehicles { get; set; }
}

public abstract class Vehicle
{
    public abstract string Type { get; }
    public string TopSpeed { get; set; }
}

public class Car : Vehicle
{
    public override string Type { get { return "Car"; } }
    public string Engine { get; set; }
}

public class Bike : Vehicle
{
    public override string Type { get { return "Bike"; } }
    public string Pedal { get; set; }
}

The challenge is how to tell Json.NET which type to use when deserializing the array. This took quite a bit of Googling on Bing to find the answer:

public abstract class JsonCreationConverter<T> : JsonConverter
{
    protected abstract T Create(Type objectType, JObject jsonObject);

    public override bool CanConvert(Type objectType)
    {
        return typeof(T).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jsonObject = JObject.Load(reader);
        var target = Create(objectType, jsonObject);
        serializer.Populate(jsonObject.CreateReader(), target);
        return target;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

public class VehicleCreationConverter : JsonCreationConverter<Vehicle>
{
    protected override Vehicle Create(Type objectType, JObject jsonObject)
    {
        string typeName = (jsonObject["type"]).ToString();
        switch (typeName)
        {
            case "Car":
                return new Car();
            case "Bike":
                return new Bike();
            default:
                return null;
        }
    }
}

I should point out that this code is not my own. I came upon the code over on StackOverflow, which was a re-post of an earlier StackOverflow question, which led me to the user ‘nonplus’ on the Json.NET discussion boards.

Many thanks to ‘nonplus’, whoever you are!

Advertisements
This entry was posted in Reference and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s