JsonInheritanceConverter
Defines the class as inheritance base class and adds a discriminator property to the serialized object.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NJsonSchema.Infrastructure;
using System;
using System.Linq;
namespace NJsonSchema.Converters
{
public class JsonInheritanceConverter : JsonConverter
{
internal static readonly string DefaultDiscriminatorName = "discriminator";
private readonly string _discriminator;
[ThreadStatic]
private static bool _isReading;
[ThreadStatic]
private static bool _isWriting;
public override bool CanWrite {
get {
if (_isWriting) {
_isWriting = false;
return false;
}
return true;
}
}
public override bool CanRead {
get {
if (_isReading) {
_isReading = false;
return false;
}
return true;
}
}
public JsonInheritanceConverter()
{
_discriminator = DefaultDiscriminatorName;
}
public JsonInheritanceConverter(string discriminator)
{
_discriminator = discriminator;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
try {
_isWriting = true;
JObject jObject = JObject.FromObject(value, serializer);
jObject.AddFirst(new JProperty(_discriminator, value.GetType().Name));
writer.WriteToken(jObject.CreateReader());
} finally {
_isWriting = false;
}
}
public override bool CanConvert(Type objectType)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jObject = serializer.Deserialize<JObject>(reader);
string discriminator = jObject.GetValue(_discriminator).Value<string>();
Type objectSubtype = GetObjectSubtype(objectType, discriminator);
try {
_isReading = true;
return serializer.Deserialize(jObject.CreateReader(), objectSubtype);
} finally {
_isReading = false;
}
}
private Type GetObjectSubtype(Type objectType, string discriminator)
{
dynamic val = (from a in ReflectionExtensions.GetCustomAttributes(objectType.GetTypeInfo(), true)
where a.GetType().Name == "KnownTypeAttribute"
select a).SingleOrDefault((Attribute a) => IsKnownTypeTargetType(a, discriminator));
if (val != null)
return (Type)val.Type;
string name = objectType.Namespace + "." + discriminator;
return objectType.GetTypeInfo().Assembly.GetType(name);
}
private bool IsKnownTypeTargetType(dynamic attribute, string discriminator)
{
return (byte)(attribute?.Type.Name == discriminator) != 0;
}
}
}