mirror of
https://github.com/meysamhadeli/booking-microservices.git
synced 2026-04-11 19:02:15 +08:00
82 lines
2.9 KiB
C#
82 lines
2.9 KiB
C#
using System.Collections.Concurrent;
|
|
using System.Reflection;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Serialization;
|
|
|
|
namespace BuildingBlocks.EventStoreDB.Serialization;
|
|
|
|
public static class JsonObjectContractProvider
|
|
{
|
|
private static readonly Type ConstructorAttributeType = typeof(JsonConstructorAttribute);
|
|
private static readonly ConcurrentDictionary<string, JsonObjectContract> Constructors = new();
|
|
|
|
public static JsonObjectContract UsingNonDefaultConstructor(
|
|
JsonObjectContract contract,
|
|
Type objectType,
|
|
Func<ConstructorInfo, JsonPropertyCollection, IList<JsonProperty>> createConstructorParameters) =>
|
|
Constructors.GetOrAdd(objectType.AssemblyQualifiedName!, _ =>
|
|
{
|
|
var nonDefaultConstructor = GetNonDefaultConstructor(objectType);
|
|
|
|
if (nonDefaultConstructor == null)
|
|
return contract;
|
|
|
|
contract.OverrideCreator = GetObjectConstructor(nonDefaultConstructor);
|
|
contract.CreatorParameters.Clear();
|
|
foreach (var constructorParameter in
|
|
createConstructorParameters(nonDefaultConstructor, contract.Properties))
|
|
{
|
|
contract.CreatorParameters.Add(constructorParameter);
|
|
}
|
|
|
|
return contract;
|
|
});
|
|
|
|
private static ObjectConstructor<object> GetObjectConstructor(MethodBase method)
|
|
{
|
|
var c = method as ConstructorInfo;
|
|
|
|
if (c == null)
|
|
return a => method.Invoke(null, a)!;
|
|
|
|
if (!c.GetParameters().Any())
|
|
return _ => c.Invoke(Array.Empty<object?>());
|
|
|
|
return a => c.Invoke(a);
|
|
}
|
|
|
|
private static ConstructorInfo? GetNonDefaultConstructor(Type objectType)
|
|
{
|
|
// Use default contract for non-object types.
|
|
if (objectType.IsPrimitive || objectType.IsEnum)
|
|
return null;
|
|
|
|
return GetAttributeConstructor(objectType)
|
|
?? GetTheMostSpecificConstructor(objectType);
|
|
}
|
|
|
|
private static ConstructorInfo? GetAttributeConstructor(Type objectType)
|
|
{
|
|
// Use default contract for non-object types.
|
|
if (objectType.IsPrimitive || objectType.IsEnum)
|
|
return null;
|
|
|
|
var constructors = objectType
|
|
.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
|
.Where(c => c.GetCustomAttributes().Any(a => a.GetType() == ConstructorAttributeType)).ToList();
|
|
|
|
return constructors.Count switch
|
|
{
|
|
1 => constructors[0],
|
|
> 1 => throw new JsonException($"Multiple constructors with a {ConstructorAttributeType.Name}."),
|
|
_ => null
|
|
};
|
|
}
|
|
|
|
private static ConstructorInfo? GetTheMostSpecificConstructor(Type objectType) =>
|
|
objectType
|
|
.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
|
.OrderByDescending(e => e.GetParameters().Length)
|
|
.FirstOrDefault();
|
|
}
|