diff options
Diffstat (limited to 'src')
6 files changed, 110 insertions, 5 deletions
diff --git a/src/Jellyfin.Extensions/Json/Converters/JsonDefaultStringEnumConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonDefaultStringEnumConverter.cs new file mode 100644 index 000000000..06ecfc558 --- /dev/null +++ b/src/Jellyfin.Extensions/Json/Converters/JsonDefaultStringEnumConverter.cs @@ -0,0 +1,49 @@ +using System; +using System.ComponentModel; +using System.Reflection; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Jellyfin.Extensions.Json.Converters; + +/// <summary> +/// Json unknown enum converter. +/// </summary> +/// <typeparam name="T">The type of enum.</typeparam> +public class JsonDefaultStringEnumConverter<T> : JsonConverter<T> + where T : struct, Enum +{ + private readonly JsonConverter<T> _baseConverter; + + /// <summary> + /// Initializes a new instance of the <see cref="JsonDefaultStringEnumConverter{T}"/> class. + /// </summary> + /// <param name="baseConverter">The base json converter.</param> + public JsonDefaultStringEnumConverter(JsonConverter<T> baseConverter) + { + _baseConverter = baseConverter; + } + + /// <inheritdoc /> + public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.IsNull() || reader.IsEmptyString()) + { + var customValueAttribute = typeToConvert.GetCustomAttribute<DefaultValueAttribute>(); + if (customValueAttribute?.Value is null) + { + throw new InvalidOperationException($"Default value not set for '{typeToConvert.Name}'"); + } + + return (T)customValueAttribute.Value; + } + + return _baseConverter.Read(ref reader, typeToConvert, options); + } + + /// <inheritdoc /> + public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + { + _baseConverter.Write(writer, value, options); + } +} diff --git a/src/Jellyfin.Extensions/Json/Converters/JsonDefaultStringEnumConverterFactory.cs b/src/Jellyfin.Extensions/Json/Converters/JsonDefaultStringEnumConverterFactory.cs new file mode 100644 index 000000000..5a9bf546e --- /dev/null +++ b/src/Jellyfin.Extensions/Json/Converters/JsonDefaultStringEnumConverterFactory.cs @@ -0,0 +1,31 @@ +using System; +using System.ComponentModel; +using System.Reflection; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Jellyfin.Extensions.Json.Converters; + +/// <summary> +/// Utilizes the JsonStringEnumConverter and sets a default value if not provided. +/// </summary> +public class JsonDefaultStringEnumConverterFactory : JsonConverterFactory +{ + private static readonly JsonStringEnumConverter _baseConverterFactory = new(); + + /// <inheritdoc /> + public override bool CanConvert(Type typeToConvert) + { + return _baseConverterFactory.CanConvert(typeToConvert) + && typeToConvert.IsDefined(typeof(DefaultValueAttribute)); + } + + /// <inheritdoc /> + public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) + { + var baseConverter = _baseConverterFactory.CreateConverter(typeToConvert, options); + var converterType = typeof(JsonDefaultStringEnumConverter<>).MakeGenericType(typeToConvert); + + return (JsonConverter?)Activator.CreateInstance(converterType, baseConverter); + } +} diff --git a/src/Jellyfin.Extensions/Json/Converters/JsonGuidConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonGuidConverter.cs index ea6d141cb..2964c6943 100644 --- a/src/Jellyfin.Extensions/Json/Converters/JsonGuidConverter.cs +++ b/src/Jellyfin.Extensions/Json/Converters/JsonGuidConverter.cs @@ -12,7 +12,7 @@ namespace Jellyfin.Extensions.Json.Converters { /// <inheritdoc /> public override Guid Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - => reader.TokenType == JsonTokenType.Null + => reader.IsNull() ? Guid.Empty : ReadInternal(ref reader); diff --git a/src/Jellyfin.Extensions/Json/Converters/JsonNullableStructConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonNullableStructConverter.cs index 28437023f..94004fa49 100644 --- a/src/Jellyfin.Extensions/Json/Converters/JsonNullableStructConverter.cs +++ b/src/Jellyfin.Extensions/Json/Converters/JsonNullableStructConverter.cs @@ -15,10 +15,7 @@ namespace Jellyfin.Extensions.Json.Converters /// <inheritdoc /> public override TStruct? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - // Token is empty string. - if (reader.TokenType == JsonTokenType.String - && ((reader.HasValueSequence && reader.ValueSequence.IsEmpty) - || (!reader.HasValueSequence && reader.ValueSpan.IsEmpty))) + if (reader.IsEmptyString()) { return null; } diff --git a/src/Jellyfin.Extensions/Json/JsonDefaults.cs b/src/Jellyfin.Extensions/Json/JsonDefaults.cs index 9e6d4c3f8..cbe5849ec 100644 --- a/src/Jellyfin.Extensions/Json/JsonDefaults.cs +++ b/src/Jellyfin.Extensions/Json/JsonDefaults.cs @@ -38,6 +38,7 @@ namespace Jellyfin.Extensions.Json new JsonNullableGuidConverter(), new JsonVersionConverter(), new JsonFlagEnumConverterFactory(), + new JsonDefaultStringEnumConverterFactory(), new JsonStringEnumConverter(), new JsonNullableStructConverterFactory(), new JsonDateTimeConverter(), diff --git a/src/Jellyfin.Extensions/Json/Utf8JsonExtensions.cs b/src/Jellyfin.Extensions/Json/Utf8JsonExtensions.cs new file mode 100644 index 000000000..d06508a26 --- /dev/null +++ b/src/Jellyfin.Extensions/Json/Utf8JsonExtensions.cs @@ -0,0 +1,27 @@ +using System.Text.Json; + +namespace Jellyfin.Extensions.Json; + +/// <summary> +/// Extensions for Utf8JsonReader and Utf8JsonWriter. +/// </summary> +public static class Utf8JsonExtensions +{ + /// <summary> + /// Determines if the reader contains an empty string. + /// </summary> + /// <param name="reader">The reader.</param> + /// <returns>Whether the reader contains an empty string.</returns> + public static bool IsEmptyString(this Utf8JsonReader reader) + => reader.TokenType == JsonTokenType.String + && ((reader.HasValueSequence && reader.ValueSequence.IsEmpty) + || (!reader.HasValueSequence && reader.ValueSpan.IsEmpty)); + + /// <summary> + /// Determines if the reader contains a null value. + /// </summary> + /// <param name="reader">The reader.</param> + /// <returns>Whether the reader contains null.</returns> + public static bool IsNull(this Utf8JsonReader reader) + => reader.TokenType == JsonTokenType.Null; +} |
