From aea83d4a3bf607348afd69d4116c0e2103721208 Mon Sep 17 00:00:00 2001 From: Vladimir Pecanac Date: Sun, 25 Oct 2026 13:32:54 +0100 Subject: [PATCH] RetrieveJSONProperty: move to .NET 10, NUnit 5 constraint model, add JsonTypeInfo name lookup Retarget both projects to net10.0, update Newtonsoft.Json to 13.0.4 and the test packages to NUnit 5.0.0, NUnit3TestAdapter 6.3.1, NUnit.Analyzers 4.15.0, Microsoft.NET.Test.Sdk 18.11.0 and coverlet.collector 10.1.0. Move the tests to Assert.That. Deserialize to Dictionary in the serialization round trip so non-string values work. Add GetSerializedPropertyNames, the Customer DTO, menu option 5 and seven tests. --- .../RetrieveJSONProperty/DTOs/Customer.cs | 14 +++ .../RetrieveJSONProperty/Helper/JsonHelper.cs | 2 +- .../Helper/JsonTextImplementation.cs | 17 ++- .../RetrieveJSONProperty/Program.cs | 16 +++ .../RetrieveJSONProperty.csproj | 4 +- .../Tests/RetrieveJSONPropertyUnitTest.cs | 116 +++++++++++++++++- .../RetrieveJSONProperty/Tests/Tests.csproj | 14 +-- 7 files changed, 168 insertions(+), 15 deletions(-) create mode 100644 json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/DTOs/Customer.cs diff --git a/json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/DTOs/Customer.cs b/json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/DTOs/Customer.cs new file mode 100644 index 0000000000..8cd7e8820a --- /dev/null +++ b/json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/DTOs/Customer.cs @@ -0,0 +1,14 @@ +using System.Text.Json.Serialization; + +namespace RetrieveJSONProperty.DTOs; + +public class Customer +{ + [JsonPropertyName("FirstName")] + public string? Name { get; set; } + + [JsonIgnore] + public string? Password { get; set; } + + public int Age { get; set; } +} diff --git a/json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/Helper/JsonHelper.cs b/json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/Helper/JsonHelper.cs index 0a7ac85cc6..037bc6ed95 100644 --- a/json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/Helper/JsonHelper.cs +++ b/json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/Helper/JsonHelper.cs @@ -22,7 +22,7 @@ public static IEnumerable RetrievalUsingSerialization(object obj) { string json = JsonConvert.SerializeObject(obj); - var values = JsonConvert.DeserializeObject>(json); + var values = JsonConvert.DeserializeObject>(json); return values != null ? values.Keys diff --git a/json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/Helper/JsonTextImplementation.cs b/json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/Helper/JsonTextImplementation.cs index d13ed00cee..31c5f6048d 100644 --- a/json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/Helper/JsonTextImplementation.cs +++ b/json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/Helper/JsonTextImplementation.cs @@ -1,4 +1,6 @@ using System.Reflection; +using System.Text.Json; +using System.Text.Json.Serialization.Metadata; using System.Text.Json.Serialization; namespace RetrieveJSONProperty.Helper; @@ -16,4 +18,17 @@ public static string[] GetJsonPropertyNames(object obj) return propertyNames; } -} \ No newline at end of file + + public static string[] GetSerializedPropertyNames(JsonSerializerOptions? options = null) + { + options ??= JsonSerializerOptions.Default; + options.MakeReadOnly(populateMissingResolver: true); + + JsonTypeInfo typeInfo = options.GetTypeInfo(typeof(T)); + + return typeInfo.Properties + .Where(property => property.Get is not null || property.Set is not null) + .Select(property => property.Name) + .ToArray(); + } +} diff --git a/json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/Program.cs b/json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/Program.cs index cd5d4bb409..14ef0d317c 100644 --- a/json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/Program.cs +++ b/json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/Program.cs @@ -11,6 +11,7 @@ Console.WriteLine("2. ListPropertywithValue"); Console.WriteLine("3. ResolverImplementation"); Console.WriteLine("4. AlternateImplementation();"); + Console.WriteLine("5. SerializerMetadataImplementation"); string? option = Console.ReadLine(); @@ -32,6 +33,10 @@ AlternateImplementation(); break; + case "5": + SerializerMetadataImplementation(); + break; + case "exit": continueExecution = false; break; @@ -92,6 +97,17 @@ static void AlternateImplementation() } } +static void SerializerMetadataImplementation() +{ + var propertyNames = JsonTextImplementation.GetSerializedPropertyNames(); + + Console.WriteLine("JSON property names:"); + foreach (var propertyName in propertyNames) + { + Console.WriteLine(propertyName); + } +} + static Sales CreateSalesObject() { Console.WriteLine("Enter YearlySales:"); diff --git a/json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/RetrieveJSONProperty.csproj b/json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/RetrieveJSONProperty.csproj index c17e0d2275..9ddf40bd52 100644 --- a/json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/RetrieveJSONProperty.csproj +++ b/json-csharp/RetrieveJSONProperty/RetrieveJSONProperty/RetrieveJSONProperty.csproj @@ -2,13 +2,13 @@ Exe - net7.0 + net10.0 enable enable - + diff --git a/json-csharp/RetrieveJSONProperty/Tests/RetrieveJSONPropertyUnitTest.cs b/json-csharp/RetrieveJSONProperty/Tests/RetrieveJSONPropertyUnitTest.cs index c100449fbb..28d36ad28e 100644 --- a/json-csharp/RetrieveJSONProperty/Tests/RetrieveJSONPropertyUnitTest.cs +++ b/json-csharp/RetrieveJSONProperty/Tests/RetrieveJSONPropertyUnitTest.cs @@ -1,3 +1,5 @@ +using System.Text.Json; + namespace Tests; [TestFixture] @@ -17,7 +19,7 @@ public void GivenObjectWithJsonPropertyAttribute_WhenRetrievalUsingReflection_Th var result = JsonHelper.RetrievalUsingReflection(sales); // Assert - CollectionAssert.AreEquivalent(new[] { "Slx_PER_Year", "Slx_PER_DAY" }, result); + Assert.That(result, Is.EquivalentTo(new[] { "Slx_PER_Year", "Slx_PER_DAY" })); } [Test] @@ -34,7 +36,20 @@ public void GivenSalesObject_WhenRetrievingKeyValuesUsingSerialization_ThenRetur var result = JsonHelper.RetrievalUsingSerialization(sales); // Assert - CollectionAssert.AreEqual(new[] { "Slx_PER_Year", "Slx_PER_DAY" }, result); + Assert.That(result, Is.EqualTo(new[] { "Slx_PER_Year", "Slx_PER_DAY" })); + } + + [Test] + public void GivenObjectWithNonStringProperty_WhenRetrievingUsingSerialization_ThenReturnsAllNames() + { + // Arrange + var testObject = new NewtonsoftObjectWithNumber { Name = "Widget", Quantity = 3 }; + + // Act + var result = JsonHelper.RetrievalUsingSerialization(testObject); + + // Assert + Assert.That(result, Is.EqualTo(new[] { "product_name", "Quantity" })); } [Test] @@ -51,6 +66,83 @@ public void Given_ObjectWithJsonPropertyAttributes_WhenGetJsonPropertyNames_Then Assert.That(result, Is.EqualTo(expected)); } + [Test] + public void GivenSalesType_WhenGetSerializedPropertyNames_ThenReturnJsonPropertyNames() + { + // Act + string[] result = JsonTextImplementation.GetSerializedPropertyNames(); + + // Assert + Assert.That(result, Is.EqualTo(new[] { "Slx_PER_Year", "Slx_PER_DAY" })); + } + + [Test] + public void GivenWebDefaults_WhenGetSerializedPropertyNames_ThenNamingPolicyAppliesOnlyWithoutAttribute() + { + // Arrange + var options = new JsonSerializerOptions(JsonSerializerDefaults.Web); + + // Act + string[] result = JsonTextImplementation.GetSerializedPropertyNames(options); + + // Assert + Assert.That(result, Is.EqualTo(new[] { "FirstName", "LastName", "age" })); + } + + [Test] + public void GivenWebDefaults_WhenSerializing_ThenOutputUsesSameNamesAsGetSerializedPropertyNames() + { + // Arrange + var options = new JsonSerializerOptions(JsonSerializerDefaults.Web); + var testObject = new TestObjectWithAttributes { Name = "Ana", Surname = "Lee", Age = 30 }; + + // Act + string json = System.Text.Json.JsonSerializer.Serialize(testObject, options); + string[] namesInJson = JsonDocument.Parse(json).RootElement + .EnumerateObject() + .Select(property => property.Name) + .ToArray(); + + // Assert + Assert.That(namesInJson, + Is.EqualTo(JsonTextImplementation.GetSerializedPropertyNames(options))); + } + + [Test] + public void GivenIgnoredProperty_WhenGetSerializedPropertyNames_ThenSkipsIt() + { + // Act + string[] result = JsonTextImplementation.GetSerializedPropertyNames(); + + // Assert + Assert.That(result, Is.EqualTo(new[] { "id" })); + } + + [Test] + public void GivenIgnoredProperty_WhenGetJsonPropertyNames_ThenReflectionStillReturnsIt() + { + // Act + string[] result = JsonTextImplementation.GetJsonPropertyNames(new ObjectWithIgnoredProperty()); + + // Assert + Assert.That(result, Is.EqualTo(new[] { "id", "Password" })); + } + + [Test] + public void GivenCustomer_WhenComparingReflectionWithWebDefaultsMetadata_ThenOnlyMetadataAppliesPolicyAndIgnore() + { + // Arrange + var webOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web); + + // Act + string[] fromReflection = JsonTextImplementation.GetJsonPropertyNames(new Customer()); + string[] fromSerializer = JsonTextImplementation.GetSerializedPropertyNames(webOptions); + + // Assert + Assert.That(fromReflection, Is.EqualTo(new[] { "FirstName", "Password", "Age" })); + Assert.That(fromSerializer, Is.EqualTo(new[] { "FirstName", "age" })); + } + [Test] public void GivenValidProductObject_WhenGettingJsonPropertyForProductName_ThenReturnCorrectProperty() { @@ -65,10 +157,9 @@ public void GivenValidProductObject_WhenGettingJsonPropertyForProductName_ThenRe var property = ResolverHelper.GetJsonProperty(sales, "Slx_per_day"); // Assert - Assert.IsNotNull(property); + Assert.That(property, Is.Not.Null); Assert.That(property.PropertyName, Is.EqualTo("Slx_PER_DAY")); Assert.That(property.PropertyType, Is.EqualTo(typeof(string))); - } private class TestObjectWithAttributes @@ -81,4 +172,21 @@ private class TestObjectWithAttributes public int Age { get; set; } } + + private class NewtonsoftObjectWithNumber + { + [JsonProperty("product_name")] + public string? Name { get; set; } + + public int Quantity { get; set; } + } + + private class ObjectWithIgnoredProperty + { + [JsonPropertyName("id")] + public int Id { get; set; } + + [System.Text.Json.Serialization.JsonIgnore] + public string? Password { get; set; } + } } diff --git a/json-csharp/RetrieveJSONProperty/Tests/Tests.csproj b/json-csharp/RetrieveJSONProperty/Tests/Tests.csproj index 23cafc2805..d3f95d58b0 100644 --- a/json-csharp/RetrieveJSONProperty/Tests/Tests.csproj +++ b/json-csharp/RetrieveJSONProperty/Tests/Tests.csproj @@ -1,7 +1,7 @@  - net7.0 + net10.0 enable enable @@ -10,12 +10,12 @@ - - - - - - + + + + + +