using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace Idoklad.Infrastructure;
///
/// Makes iDoklad SDK models usable in both directions. The SDK only ever serializes what it sends
/// and deserializes what it receives, so several of its converters, attached through
/// , implement one direction and throw
/// in the other. This service needs both directions, so this
/// resolver swaps those converters for wrappers that fill in the missing half. Everything else is
/// left to .
///
public sealed class SdkContractResolver : DefaultContractResolver
{
///
/// SDK converters that cannot write, so responses carrying such a model would fail.
///
private static readonly HashSet WriteUnsupportedConverterTypeNames = new(StringComparer.Ordinal)
{
// Attached to DateTime members of the invoice, bank account, cash register and similar models.
"IdokladSdk.Serialization.DateTimeConverter",
// Attached to the NotificationListGetModel type itself.
"IdokladSdk.Serialization.NotificationJsonConverter",
};
///
/// SDK converters that cannot read, so a request body carrying such a member would fail.
///
private const string NullablePropertyConverterTypeName = "IdokladSdk.Clients.NullablePropertyJsonConverter";
protected override JsonContract CreateContract(Type objectType)
{
var contract = base.CreateContract(objectType);
contract.Converter = Replace(contract.Converter);
return contract;
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
property.Converter = Replace(property.Converter);
// Collections carry the member converter as the item converter instead.
property.ItemConverter = Replace(property.ItemConverter);
return property;
}
private static JsonConverter? Replace(JsonConverter? converter)
{
var typeName = converter?.GetType().FullName;
if (typeName is null)
{
return converter;
}
if (WriteUnsupportedConverterTypeNames.Contains(typeName))
{
return new SdkWriteBypassJsonConverter(converter!);
}
// Attached to NullableProperty members of Patch models; writing works, reading throws.
return typeName == NullablePropertyConverterTypeName
? new SdkNullablePropertyConverter(converter!)
: converter;
}
}