From 5bc984fe07a77a36de519a2072c097ed6f50420b Mon Sep 17 00:00:00 2001 From: Matthew Steeples Date: Thu, 26 Aug 2021 23:58:28 +0100 Subject: [PATCH] Add a Converter to serialize empty strings as null values Allows these values to be excluded when `IgnoreNullValues` is True --- .../JsonEmptyStringToNullConverter.cs | 26 +++++++ .../JsonEmptyStringToNullConverterTests.cs | 73 +++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 ClassLibraries/Macross.Json.Extensions/Code/System.Text.Json.Serialization/JsonEmptyStringToNullConverter.cs create mode 100644 ClassLibraries/Macross.Json.Extensions/Test/JsonEmptyStringToNullConverterTests.cs diff --git a/ClassLibraries/Macross.Json.Extensions/Code/System.Text.Json.Serialization/JsonEmptyStringToNullConverter.cs b/ClassLibraries/Macross.Json.Extensions/Code/System.Text.Json.Serialization/JsonEmptyStringToNullConverter.cs new file mode 100644 index 0000000..beeb54d --- /dev/null +++ b/ClassLibraries/Macross.Json.Extensions/Code/System.Text.Json.Serialization/JsonEmptyStringToNullConverter.cs @@ -0,0 +1,26 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Macross.Json.Extensions.System.Text.Json.Serialization +{ + /// + /// to output empty strings as null values. + /// + public class JsonEmptyStringToNullConverter : JsonConverter + { + /// + public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => reader.GetString(); + + /// + public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) + { +#pragma warning disable CA1062 // Don't perform checks for performance. Trust our callers will be nice. + if (string.IsNullOrEmpty(value)) + writer.WriteNullValue(); + else + writer.WriteStringValue(value); +#pragma warning restore CA1062 // Validate arguments of public methods + } + } +} diff --git a/ClassLibraries/Macross.Json.Extensions/Test/JsonEmptyStringToNullConverterTests.cs b/ClassLibraries/Macross.Json.Extensions/Test/JsonEmptyStringToNullConverterTests.cs new file mode 100644 index 0000000..27e5728 --- /dev/null +++ b/ClassLibraries/Macross.Json.Extensions/Test/JsonEmptyStringToNullConverterTests.cs @@ -0,0 +1,73 @@ +using System.Text.Json; + +using Macross.Json.Extensions.System.Text.Json.Serialization; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Macross.Json.Extensions.Tests +{ + [TestClass] + public class JsonEmptyStringToNullConverterTests + { + private const string? NullString = null; + + [TestMethod] + public void TestNullIsOutputForEmptyString() + { + JsonSerializerOptions options = new JsonSerializerOptions(); + options.Converters.Add(new JsonEmptyStringToNullConverter()); + + string Json = JsonSerializer.Serialize("Test", options); + Assert.AreEqual(@"""Test""", Json); + + Json = JsonSerializer.Serialize(string.Empty, options); + Assert.AreEqual("null", Json); + + Json = JsonSerializer.Serialize(NullString, options); + Assert.AreEqual("null", Json); + + Json = JsonSerializer.Serialize(new TestClass(), options); + Assert.AreEqual("{\"Str1\":null,\"Str2\":null}", Json); + + Json = JsonSerializer.Serialize(new TestClass() { Str1 = "One" }, options); + Assert.AreEqual("{\"Str1\":\"One\",\"Str2\":null}", Json); + + Json = JsonSerializer.Serialize(new TestClass() { Str1 = "One", Str2 = "Two" }, options); + Assert.AreEqual("{\"Str1\":\"One\",\"Str2\":\"Two\"}", Json); + + Json = JsonSerializer.Serialize(new TestClass() { Str2 = "Two" }, options); + Assert.AreEqual("{\"Str1\":null,\"Str2\":\"Two\"}", Json); + + options = new JsonSerializerOptions(); + options.Converters.Add(new JsonEmptyStringToNullConverter()); + options.IgnoreNullValues = true; + + Json = JsonSerializer.Serialize("Test", options); + Assert.AreEqual(@"""Test""", Json); + + Json = JsonSerializer.Serialize(string.Empty, options); + Assert.AreEqual("null", Json); + + Json = JsonSerializer.Serialize(NullString, options); + Assert.AreEqual("null", Json); + + Json = JsonSerializer.Serialize(new TestClass(), options); + Assert.AreEqual("{}", Json); + + Json = JsonSerializer.Serialize(new TestClass() { Str1 = "One" }, options); + Assert.AreEqual("{\"Str1\":\"One\"}", Json); + + Json = JsonSerializer.Serialize(new TestClass() { Str1 = "One", Str2 = "Two" }, options); + Assert.AreEqual("{\"Str1\":\"One\",\"Str2\":\"Two\"}", Json); + + Json = JsonSerializer.Serialize(new TestClass() { Str2 = "Two" }, options); + Assert.AreEqual("{\"Str2\":\"Two\"}", Json); + } + + private class TestClass + { + public string? Str1 { get; set; } + + public string? Str2 { get; set; } + } + } +}