Headless CMS and Content Managment Hub
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

136 lines
3.7 KiB

// ==========================================================================
// JsonInheritanceConverter.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NJsonSchema.Annotations;
#pragma warning disable SA1306 // Field names must begin with lower-case letter
namespace Squidex.Areas.Api.Controllers
{
public sealed class JsonInheritanceConverter : JsonConverter
{
private readonly string discriminator;
[ThreadStatic]
private static bool IsReading;
[ThreadStatic]
private static bool IsWriting;
public override bool CanWrite
{
get
{
if (!IsWriting)
{
return true;
}
return IsWriting = false;
}
}
public override bool CanRead
{
get
{
if (!IsReading)
{
return true;
}
return IsReading = false;
}
}
public JsonInheritanceConverter(string discriminator)
{
this.discriminator = discriminator;
}
public override bool CanConvert(Type objectType)
{
return true;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
IsWriting = true;
try
{
var jsonObject = JObject.FromObject(value, serializer);
jsonObject.AddFirst(new JProperty(discriminator, GetSchemaName(value.GetType())));
writer.WriteToken(jsonObject.CreateReader());
}
finally
{
IsWriting = false;
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
IsReading = true;
try
{
var jsonObject = serializer.Deserialize<JObject>(reader);
var subName = jsonObject[discriminator]?.Value<string>();
if (subName == null)
{
return null;
}
var subType = GetObjectSubtype(objectType, subName);
if (subType == null)
{
return null;
}
return serializer.Deserialize(jsonObject.CreateReader(), subType);
}
finally
{
IsReading = false;
}
}
private static Type GetObjectSubtype(Type objectType, string discriminatorValue)
{
var knownTypeAttribute =
objectType.GetTypeInfo().GetCustomAttributes<KnownTypeAttribute>()
.FirstOrDefault(a => IsKnownType(a, discriminatorValue));
return knownTypeAttribute?.Type;
}
private static bool IsKnownType(KnownTypeAttribute attribute, string discriminator)
{
var type = attribute.Type;
return type != null && GetSchemaName(type) == discriminator;
}
private static string GetSchemaName(Type type)
{
var schenaName = type.GetTypeInfo().GetCustomAttribute<JsonSchemaAttribute>()?.Name;
return schenaName ?? type.Name;
}
}
}