oprava konvertoru
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Idoklad.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// Makes iDoklad SDK models serializable. Some SDK converters, attached through
|
||||
/// <see cref="JsonConverterAttribute"/>, only support reading and their <c>WriteJson</c> throws
|
||||
/// <see cref="NotImplementedException"/>, which turns any response carrying such a model into a
|
||||
/// 500. This resolver replaces them with <see cref="SdkWriteBypassJsonConverter"/>: reading keeps
|
||||
/// using the SDK converter, writing falls back to the standard serialization. Everything else is
|
||||
/// left to <see cref="DefaultContractResolver"/>.
|
||||
/// </summary>
|
||||
public sealed class SdkContractResolver : DefaultContractResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// SDK converters that cannot write. Converters that do implement writing (for example
|
||||
/// <c>NullablePropertyJsonConverter</c>) are deliberately not listed here.
|
||||
/// </summary>
|
||||
private static readonly HashSet<string> 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",
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
return typeName is not null && WriteUnsupportedConverterTypeNames.Contains(typeName)
|
||||
? new SdkWriteBypassJsonConverter(converter!)
|
||||
: converter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Idoklad.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// Wraps an iDoklad SDK converter that only supports reading. Reading is delegated to the SDK
|
||||
/// converter, while <see cref="CanWrite"/> is false, so Newtonsoft writes the value with the
|
||||
/// standard member-by-member serialization instead of calling the SDK's <c>WriteJson</c>.
|
||||
/// </summary>
|
||||
public sealed class SdkWriteBypassJsonConverter : JsonConverter
|
||||
{
|
||||
private readonly JsonConverter _sdkConverter;
|
||||
|
||||
public SdkWriteBypassJsonConverter(JsonConverter sdkConverter)
|
||||
{
|
||||
_sdkConverter = sdkConverter;
|
||||
}
|
||||
|
||||
public override bool CanRead => _sdkConverter.CanRead;
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override bool CanConvert(Type objectType) => _sdkConverter.CanConvert(objectType);
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
=> _sdkConverter.ReadJson(reader, objectType, existingValue, serializer);
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
=> throw new InvalidOperationException("CanWrite is false; Newtonsoft must not call this converter for writing.");
|
||||
}
|
||||
Reference in New Issue
Block a user