From 6828245e9496ee116bdb820178103d34df421429 Mon Sep 17 00:00:00 2001 From: Ionite Date: Wed, 24 Jan 2024 17:21:22 -0500 Subject: [PATCH] Improved converters --- .../Json/ParsableStringValueJsonConverter.cs | 97 +++++++++++++++++++ .../Converters/Json/StringJsonConverter.cs | 45 ++++++++- 2 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 StabilityMatrix.Core/Converters/Json/ParsableStringValueJsonConverter.cs diff --git a/StabilityMatrix.Core/Converters/Json/ParsableStringValueJsonConverter.cs b/StabilityMatrix.Core/Converters/Json/ParsableStringValueJsonConverter.cs new file mode 100644 index 00000000..ac1ab51e --- /dev/null +++ b/StabilityMatrix.Core/Converters/Json/ParsableStringValueJsonConverter.cs @@ -0,0 +1,97 @@ +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Serialization; +using StabilityMatrix.Core.Models; + +namespace StabilityMatrix.Core.Converters.Json; + +public class ParsableStringValueJsonConverter< + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T +> : JsonConverter + where T : StringValue, IParsable +{ + /// + public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.String) + { + throw new JsonException(); + } + + var value = reader.GetString(); + if (value is null) + { + return default; + } + + // Use TryParse result if available + if (T.TryParse(value, CultureInfo.InvariantCulture, out var result)) + { + return result; + } + + // Otherwise use Activator + return (T?)Activator.CreateInstance(typeToConvert, value); + } + + /// + public override T ReadAsPropertyName( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options + ) + { + if (reader.TokenType != JsonTokenType.String) + { + throw new JsonException(); + } + + var value = reader.GetString(); + if (value is null) + { + throw new JsonException("Property name cannot be null"); + } + + // Use TryParse result if available + if (T.TryParse(value, CultureInfo.InvariantCulture, out var result)) + { + return result; + } + + // Otherwise use Activator + return (T?)Activator.CreateInstance(typeToConvert, value) + ?? throw new JsonException("Property name cannot be null"); + } + + /// + public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + { + if (value is IFormattable formattable) + { + writer.WriteStringValue(formattable.ToString(null, CultureInfo.InvariantCulture)); + } + else + { + writer.WriteStringValue(value.ToString()); + } + } + + /// + public override void WriteAsPropertyName(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + { + if (value is null) + { + throw new JsonException("Property name cannot be null"); + } + + if (value is IFormattable formattable) + { + writer.WriteStringValue(formattable.ToString(null, CultureInfo.InvariantCulture)); + } + else + { + writer.WriteStringValue(value.ToString()); + } + } +} diff --git a/StabilityMatrix.Core/Converters/Json/StringJsonConverter.cs b/StabilityMatrix.Core/Converters/Json/StringJsonConverter.cs index c7a4a20b..03eb8cfd 100644 --- a/StabilityMatrix.Core/Converters/Json/StringJsonConverter.cs +++ b/StabilityMatrix.Core/Converters/Json/StringJsonConverter.cs @@ -12,8 +12,9 @@ namespace StabilityMatrix.Core.Converters.Json; /// Types implementing will be formatted with /// [PublicAPI] -public class StringJsonConverter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T> - : JsonConverter +public class StringJsonConverter< + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T +> : JsonConverter { /// public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) @@ -32,6 +33,28 @@ public class StringJsonConverter<[DynamicallyAccessedMembers(DynamicallyAccessed return (T?)Activator.CreateInstance(typeToConvert, value); } + /// + public override T ReadAsPropertyName( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options + ) + { + if (reader.TokenType != JsonTokenType.String) + { + throw new JsonException(); + } + + var value = reader.GetString(); + if (value is null) + { + throw new JsonException("Property name cannot be null"); + } + + return (T?)Activator.CreateInstance(typeToConvert, value) + ?? throw new JsonException("Property name cannot be null"); + } + /// public override void Write(Utf8JsonWriter writer, T? value, JsonSerializerOptions options) { @@ -50,4 +73,22 @@ public class StringJsonConverter<[DynamicallyAccessedMembers(DynamicallyAccessed writer.WriteStringValue(value.ToString()); } } + + /// + public override void WriteAsPropertyName(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + { + if (value is null) + { + throw new JsonException("Property name cannot be null"); + } + + if (value is IFormattable formattable) + { + writer.WriteStringValue(formattable.ToString(null, CultureInfo.InvariantCulture)); + } + else + { + writer.WriteStringValue(value.ToString()); + } + } }