JsonSubTypes 2.0.1

.NET Standard 1.3 .NET Framework 3.5
dotnet add package JsonSubTypes --version 2.0.1
NuGet\Install-Package JsonSubTypes -Version 2.0.1
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="JsonSubTypes" Version="2.0.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add JsonSubTypes --version 2.0.1
#r "nuget: JsonSubTypes, 2.0.1"
#r directive can be used in F# Interactive, C# scripting and .NET Interactive. Copy this into the interactive tool or source code of the script to reference the package.
// Install JsonSubTypes as a Cake Addin
#addin nuget:?package=JsonSubTypes&version=2.0.1

// Install JsonSubTypes as a Cake Tool
#tool nuget:?package=JsonSubTypes&version=2.0.1

JsonSubTypes

JsonSubTypes is a discriminated Json sub-type Converter implementation for .NET

Build status Code Coverage Quality Gate Status NuGet NuGet CodeFactor FOSSA Status

DeserializeObject with custom type property name

[JsonConverter(typeof(JsonSubtypes), "Kind")]
public interface IAnimal
{
    string Kind { get; }
}

public class Dog : IAnimal
{
    public string Kind { get; } = "Dog";
    public string Breed { get; set; }
}

public class Cat : IAnimal {
    public string Kind { get; } = "Cat";
    public bool Declawed { get; set;}
}

The second parameter of the JsonConverter attribute is the JSON property name that will be use to retreive the type information from JSON.

var animal = JsonConvert.DeserializeObject<IAnimal>("{\"Kind\":\"Dog\",\"Breed\":\"Jack Russell Terrier\"}");
Assert.AreEqual("Jack Russell Terrier", (animal as Dog)?.Breed);

N.B.: This only works for types in the same assembly as the base type/interface and either in the same namespace or with a fully qualified type name.

DeserializeObject with custom type mapping

[JsonConverter(typeof(JsonSubtypes), "Sound")]
[JsonSubtypes.KnownSubType(typeof(Dog), "Bark")]
[JsonSubtypes.KnownSubType(typeof(Cat), "Meow")]
public class Animal
{
    public virtual string Sound { get; }
    public string Color { get; set; }
}

public class Dog : Animal
{
    public override string Sound { get; } = "Bark";
    public string Breed { get; set; }
}

public class Cat : Animal
{
    public override string Sound { get; } = "Meow";
    public bool Declawed { get; set; }
}
var animal = JsonConvert.DeserializeObject<IAnimal>("{\"Sound\":\"Bark\",\"Breed\":\"Jack Russell Terrier\"}");
Assert.AreEqual("Jack Russell Terrier", (animal as Dog)?.Breed);

N.B.: Also works with other kind of value than string, i.e.: enums, int, ...

SerializeObject and DeserializeObject with custom type property only present in JSON

This mode of operation only works when JsonSubTypes is explicitely registered in JSON.NET's serializer settings, and not through the [JsonConverter] attribute.

public abstract class Animal
{
    public int Age { get; set; }
}

public class Dog : Animal
{
    public bool CanBark { get; set; } = true;
}

public class Cat : Animal
{
    public int Lives { get; set; } = 7;
}

public enum AnimalType
{
    Dog = 1,
    Cat = 2
}

Registration:

var settings = new JsonSerializerSettings();
settings.Converters.Add(JsonSubtypesConverterBuilder
    .Of(typeof(Animal), "Type") // type property is only defined here
    .RegisterSubtype(typeof(Cat), AnimalType.Cat)
    .RegisterSubtype(typeof(Dog), AnimalType.Dog)
    .SerializeDiscriminatorProperty() // ask to serialize the type property
    .Build());

or using syntax with generics:

var settings = new JsonSerializerSettings();
settings.Converters.Add(JsonSubtypesConverterBuilder
    .Of<Animal>("Type") // type property is only defined here
    .RegisterSubtype<Cat>(AnimalType.Cat)
    .RegisterSubtype<Dog>(AnimalType.Dog)
    .SerializeDiscriminatorProperty() // ask to serialize the type property
    .Build());

De-/Serialization:

var cat = new Cat { Age = 11, Lives = 6 }

var json = JsonConvert.SerializeObject(cat, settings);

Assert.Equal("{\"Lives\":6,\"Age\":11,\"Type\":2}", json);

var result = JsonConvert.DeserializeObject<Animal>(json, settings);

Assert.Equal(typeof(Cat), result.GetType());
Assert.Equal(11, result.Age);
Assert.Equal(6, (result as Cat)?.Lives);

DeserializeObject mapping by property presence

[JsonConverter(typeof(JsonSubtypes))]
[JsonSubtypes.KnownSubTypeWithProperty(typeof(Employee), "JobTitle")]
[JsonSubtypes.KnownSubTypeWithProperty(typeof(Artist), "Skill")]
public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class Employee : Person
{
    public string Department { get; set; }
    public string JobTitle { get; set; }
}

public class Artist : Person
{
    public string Skill { get; set; }
}

or using syntax with generics:

string json = "[{\"Department\":\"Department1\",\"JobTitle\":\"JobTitle1\",\"FirstName\":\"FirstName1\",\"LastName\":\"LastName1\"}," +
                "{\"Department\":\"Department1\",\"JobTitle\":\"JobTitle1\",\"FirstName\":\"FirstName1\",\"LastName\":\"LastName1\"}," +
                "{\"Skill\":\"Painter\",\"FirstName\":\"FirstName1\",\"LastName\":\"LastName1\"}]";


var persons = JsonConvert.DeserializeObject<IReadOnlyCollection<Person>>(json);
Assert.AreEqual("Painter", (persons.Last() as Artist)?.Skill);

Registration:

settings.Converters.Add(JsonSubtypesWithPropertyConverterBuilder
    .Of(typeof(Person))
    .RegisterSubtypeWithProperty(typeof(Employee), "JobTitle")
    .RegisterSubtypeWithProperty(typeof(Artist), "Skill")
    .Build());

or

settings.Converters.Add(JsonSubtypesWithPropertyConverterBuilder
    .Of<Person>()
    .RegisterSubtypeWithProperty<Employee>("JobTitle")
    .RegisterSubtypeWithProperty<Artist>("Skill")
    .Build());

A default class other than the base type can be defined

[JsonConverter(typeof(JsonSubtypes))]
[JsonSubtypes.KnownSubType(typeof(ConstantExpression), "Constant")]
[JsonSubtypes.FallBackSubType(typeof(UnknownExpression))]
public interface IExpression
{
    string Type { get; }
}

Or with code configuration:

settings.Converters.Add(JsonSubtypesConverterBuilder
    .Of(typeof(IExpression), "Type")
    .SetFallbackSubtype(typeof(UnknownExpression))
    .RegisterSubtype(typeof(ConstantExpression), "Constant")
    .Build());
settings.Converters.Add(JsonSubtypesWithPropertyConverterBuilder
    .Of(typeof(IExpression))
    .SetFallbackSubtype(typeof(UnknownExpression))
    .RegisterSubtype(typeof(ConstantExpression), "Value")
    .Build());

šŸ’– Support this project

If this project helped you save money or time or simply makes your life also easier, you can give me a cup of coffee =)

  • Support via PayPal
  • Bitcoin ā€” You can send me bitcoins at this address: 33gxVjey6g4Beha26fSQZLFfWWndT1oY3F

License

FOSSA Status

Product Versions
.NET net5.0 net5.0-windows net6.0 net6.0-android net6.0-ios net6.0-maccatalyst net6.0-macos net6.0-tvos net6.0-windows
.NET Core netcoreapp1.0 netcoreapp1.1 netcoreapp2.0 netcoreapp2.1 netcoreapp2.2 netcoreapp3.0 netcoreapp3.1
.NET Standard netstandard1.3 netstandard1.4 netstandard1.5 netstandard1.6 netstandard2.0 netstandard2.1
.NET Framework net35 net40 net403 net45 net451 net452 net46 net461 net462 net463 net47 net471 net472 net48
MonoAndroid monoandroid
MonoMac monomac
MonoTouch monotouch
Tizen tizen30 tizen40 tizen60
Universal Windows Platform uap uap10.0
Xamarin.iOS xamarinios
Xamarin.Mac xamarinmac
Xamarin.TVOS xamarintvos
Xamarin.WatchOS xamarinwatchos
Compatible target framework(s)
Additional computed target framework(s)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (545)

Showing the top 5 NuGet packages that depend on JsonSubTypes:

Package Downloads
Okta.Sdk

Official .NET SDK for the Okta API

Xero.NetStandard.OAuth2

This is a .NETStandard SDK library, used to communicate with the Xero API using OAuth2.0. See https://github.com/XeroAPI/Xero-NetStandard for more information

Lusid.Sdk.Preview

LUSID SDK

Lusid.Sdk

LUSID SDK

InfluxDB.Client

The reference client that allows query, write and management (bucket, organization, users) for the InfluxDB 2.x.

GitHub repositories (15)

Showing the top 5 popular GitHub repositories that depend on JsonSubTypes:

Repository Stars
BililiveRecorder/BililiveRecorder
Bē«™å½•ę’­å§¬ | BiliBili Stream Recorder | 哔哩哔哩ē›“ę’­å½•åˆ¶
antonpup/Aurora
Unified lighting effects across multiple brands and various games.
Azure-Samples/cognitive-services-speech-sdk
Sample code for the Microsoft Cognitive Services Speech SDK
RyanLamansky/dotnet-webassembly
Create, read, modify, write and execute WebAssembly (WASM) files from .NET-based applications.
jlucansky/Quartzmin
Quartzmin is powerful, easy to use web management tool for Quartz.NET
Version Downloads Last updated
2.0.1 90,020 10/18/2022
2.0.0 219 10/18/2022
1.9.0 835,621 5/9/2022
1.8.0 7,613,653 9/23/2020
1.7.0 1,860,409 3/28/2020
1.6.0 2,387,802 6/24/2019
1.5.2 2,920,780 1/19/2019
1.5.1 311,810 10/15/2018
1.5.0 87,925 8/27/2018
1.4.0 136,332 4/17/2018
1.3.1 4,584 4/12/2018
1.3.0 50,246 1/28/2018
1.2.0 4,750,450 11/22/2017
1.1.3 46,829 11/15/2017
1.1.2 1,790 10/20/2017
1.1.1 1,455 9/21/2017
1.1.0 6,395 9/19/2017
1.0.0 2,991 7/23/2017