From b4d81b0f9ba5077e446662ce14fec3e506d106ce Mon Sep 17 00:00:00 2001 From: Twan Jacobs Date: Mon, 15 Aug 2022 15:21:11 +0200 Subject: [PATCH] Fix output of JsonIgnore attributes (#1522) * Fix output of JsonIgnore attributes * Recognize Guid as value type * Rename variable * Use JsonFormatStrings for ValueTypeFormats * Easier fix * Remove unused field --- .../GeneralGeneratorTests.cs | 126 ------------- .../JsonIgnoreAttributesTests.cs | 177 ++++++++++++++++++ .../Models/PropertyModel.cs | 9 +- 3 files changed, 182 insertions(+), 130 deletions(-) create mode 100644 src/NJsonSchema.CodeGeneration.CSharp.Tests/JsonIgnoreAttributesTests.cs diff --git a/src/NJsonSchema.CodeGeneration.CSharp.Tests/GeneralGeneratorTests.cs b/src/NJsonSchema.CodeGeneration.CSharp.Tests/GeneralGeneratorTests.cs index bc0b442ee..a70d2ccb1 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp.Tests/GeneralGeneratorTests.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp.Tests/GeneralGeneratorTests.cs @@ -739,132 +739,6 @@ public async Task When_property_is_required_then_CSharp_code_is_correct() AssertCompile(code); } - [Fact] - public async Task When_using_SystemTextJson_JsonIgnoreAttributes_are_generated_based_on_optionality() { - //// Arrange - var schema = await JsonSchema.FromJsonAsync(@"{ - ""type"": ""object"", - ""required"": [""requiredValue"",""requiredRef""], - ""properties"": { - ""requiredValue"": { ""type"": ""integer"", ""format"": ""int32"" }, - ""requiredRef"": { ""type"": ""string"" }, - ""optionalValue"": { ""type"": ""integer"", ""format"": ""int32"" }, - ""optionalRef"": { ""type"": ""string"" } - } - }"); - - var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings { - JsonLibrary = CSharpJsonLibrary.SystemTextJson - }); - - static string Normalized(string str) => - Regex.Replace(str, @"\s+", " "); - - //// Act - var code = generator.GenerateFile("MyClass"); - - /// Assert - Assert.Contains( - Normalized(@"public int OptionalValue {"), - Normalized(code) - ); - - Assert.Contains( - Normalized(@" - [System.Text.Json.Serialization.JsonPropertyName(""requiredValue"")] - [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.Never)] - "), - Normalized(code) - ); - - Assert.Contains( - Normalized(@" - [System.Text.Json.Serialization.JsonPropertyName(""requiredRef"")] - [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.Never)] - "), - Normalized(code) - ); - - Assert.Contains( - Normalized(@" - [System.Text.Json.Serialization.JsonPropertyName(""optionalValue"")] - [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] - "), - Normalized(code) - ); - - Assert.Contains( - Normalized(@" - [System.Text.Json.Serialization.JsonPropertyName(""optionalRef"")] - [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] - "), - Normalized(code) - ); - } - - [Fact] - public async Task When_using_SystemTextJson_and_RequiredPropertiesMustBeDefined_is_false_JsonIgnoreAttributes_are_not_generated_for_required_properties() { - //// Arrange - var schema = await JsonSchema.FromJsonAsync(@"{ - ""type"": ""object"", - ""required"": [""required""], - ""properties"": { - ""required"": { ""type"": ""string"" } - } - }"); - - var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings { - JsonLibrary = CSharpJsonLibrary.SystemTextJson, - RequiredPropertiesMustBeDefined = false - }); - - static string Normalized(string str) => - Regex.Replace(str, @"\s+", " "); - - //// Act - var code = generator.GenerateFile("MyClass"); - - /// Assert - Assert.DoesNotContain( - Normalized(@" - [System.Text.Json.Serialization.JsonIgnore - "), - Normalized(code) - ); - } - - [Fact] - public async Task When_using_SystemTextJson_and_RequiredPropertiesMustBeDefined_is_false_JsonIgnoreAttributes_are_still_generated_for_optional_properties() { - //// Arrange - var schema = await JsonSchema.FromJsonAsync(@"{ - ""type"": ""object"", - ""required"": [], - ""properties"": { - ""optional"": { ""type"": ""string"" } - } - }"); - - var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings { - JsonLibrary = CSharpJsonLibrary.SystemTextJson, - RequiredPropertiesMustBeDefined = false - }); - - static string Normalized(string str) => - Regex.Replace(str, @"\s+", " "); - - //// Act - var code = generator.GenerateFile("MyClass"); - - /// Assert - Assert.Contains( - Normalized(@" - [System.Text.Json.Serialization.JsonPropertyName(""optional"")] - [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] - "), - Normalized(code) - ); - } - [Fact] public void When_array_property_is_required_or_not_then_the_code_has_correct_initializer() { diff --git a/src/NJsonSchema.CodeGeneration.CSharp.Tests/JsonIgnoreAttributesTests.cs b/src/NJsonSchema.CodeGeneration.CSharp.Tests/JsonIgnoreAttributesTests.cs new file mode 100644 index 000000000..f5125244e --- /dev/null +++ b/src/NJsonSchema.CodeGeneration.CSharp.Tests/JsonIgnoreAttributesTests.cs @@ -0,0 +1,177 @@ +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Xunit; + +namespace NJsonSchema.CodeGeneration.CSharp.Tests +{ + public class JsonIgnoreAttributesTests + { + [Fact] + public async Task When_using_SystemTextJson_JsonIgnoreAttributes_are_generated_based_on_optionality() + { + //// Arrange + var schema = await JsonSchema.FromJsonAsync(@"{ + ""type"": ""object"", + ""required"": [""requiredValue"",""requiredNullableValue"",""requiredRef""], + ""properties"": { + ""requiredValue"": { ""type"": ""integer"", ""format"": ""int32"" }, + ""requiredNullableValue"": { ""type"": [""integer"", ""null""], ""format"": ""int32"" }, + ""requiredRef"": { ""type"": ""string"" }, + ""optionalValue"": { ""type"": ""integer"", ""format"": ""int32"" }, + ""optionalNullableValue"": { ""type"": [""integer"", ""null""], ""format"": ""int32"" }, + ""optionalRef"": { ""type"": ""string"" } + } + }"); + + var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings + { + JsonLibrary = CSharpJsonLibrary.SystemTextJson, + }); + + static string Normalized(string str) => + Regex.Replace(str, @"\s+", " "); + + //// Act + var code = generator.GenerateFile("MyClass"); + + /// Assert + Assert.Contains( + Normalized(@"public int OptionalValue {"), + Normalized(code) + ); + + Assert.Contains( + Normalized(@" + [System.Text.Json.Serialization.JsonPropertyName(""requiredValue"")] + [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.Never)] + "), + Normalized(code) + ); + + Assert.Contains( + Normalized(@" + [System.Text.Json.Serialization.JsonPropertyName(""requiredNullableValue"")] + [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.Never)] + "), + Normalized(code) + ); + + Assert.Contains( + Normalized(@" + [System.Text.Json.Serialization.JsonPropertyName(""requiredRef"")] + [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.Never)] + "), + Normalized(code) + ); + + Assert.Contains( + Normalized(@" + [System.Text.Json.Serialization.JsonPropertyName(""optionalValue"")] + [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault)] + "), + Normalized(code) + ); + + Assert.Contains( + Normalized(@" + [System.Text.Json.Serialization.JsonPropertyName(""optionalNullableValue"")] + [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault)] + "), + Normalized(code) + ); + + Assert.Contains( + Normalized(@" + [System.Text.Json.Serialization.JsonPropertyName(""optionalRef"")] + [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault)] + "), + Normalized(code) + ); + } + + [Fact] + public async Task When_using_SystemTextJson_and_RequiredPropertiesMustBeDefined_is_false_JsonIgnoreAttributes_are_not_generated_for_required_properties() + { + //// Arrange + var schema = await JsonSchema.FromJsonAsync(@"{ + ""type"": ""object"", + ""required"": [""required""], + ""properties"": { + ""required"": { ""type"": ""string"" } + } + }"); + + var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings + { + JsonLibrary = CSharpJsonLibrary.SystemTextJson, + RequiredPropertiesMustBeDefined = false + }); + + static string Normalized(string str) => + Regex.Replace(str, @"\s+", " "); + + //// Act + var code = generator.GenerateFile("MyClass"); + + /// Assert + Assert.DoesNotContain( + Normalized(@" + [System.Text.Json.Serialization.JsonIgnore + "), + Normalized(code) + ); + } + + [Fact] + public async Task When_using_SystemTextJson_and_RequiredPropertiesMustBeDefined_is_false_JsonIgnoreAttributes_are_still_generated_for_optional_properties() + { + //// Arrange + var schema = await JsonSchema.FromJsonAsync(@"{ + ""type"": ""object"", + ""required"": [], + ""properties"": { + ""optionalRef"": { ""type"": ""string"" }, + ""optionalValue"": { ""type"": ""integer"", ""format"": ""int32"" }, + ""optionalNullableValue"": { ""type"": [""integer"", ""null""], ""format"": ""int32"" } + } + }"); + + var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings + { + JsonLibrary = CSharpJsonLibrary.SystemTextJson, + RequiredPropertiesMustBeDefined = false + }); + + static string Normalized(string str) => + Regex.Replace(str, @"\s+", " "); + + //// Act + var code = generator.GenerateFile("MyClass"); + + /// Assert + Assert.Contains( + Normalized(@" + [System.Text.Json.Serialization.JsonPropertyName(""optionalRef"")] + [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault)] + "), + Normalized(code) + ); + + Assert.Contains( + Normalized(@" + [System.Text.Json.Serialization.JsonPropertyName(""optionalValue"")] + [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault)] + "), + Normalized(code) + ); + + Assert.Contains( + Normalized(@" + [System.Text.Json.Serialization.JsonPropertyName(""optionalNullableValue"")] + [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault)] + "), + Normalized(code) + ); + } + } +} diff --git a/src/NJsonSchema.CodeGeneration.CSharp/Models/PropertyModel.cs b/src/NJsonSchema.CodeGeneration.CSharp/Models/PropertyModel.cs index 185392862..62b3d8f35 100644 --- a/src/NJsonSchema.CodeGeneration.CSharp/Models/PropertyModel.cs +++ b/src/NJsonSchema.CodeGeneration.CSharp/Models/PropertyModel.cs @@ -64,17 +64,18 @@ public PropertyModel( (_property.ActualTypeSchema.IsArray && _settings.GenerateImmutableArrayProperties) || (_property.ActualTypeSchema.IsDictionary && _settings.GenerateImmutableDictionaryProperties) )) == false; - + /// Indicates whether or not this property has a . public bool HasJsonIgnoreCondition => JsonIgnoreCondition != null; /// Returns the System.Text.Json.Serialization.JsonIgnoreCondition value to be applied to the property. - public string JsonIgnoreCondition => _property switch { - { IsRequired: false } => "System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull", + public string JsonIgnoreCondition => _property switch + { + { IsRequired: false } => "System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault", { IsRequired: true } when _settings.RequiredPropertiesMustBeDefined => "System.Text.Json.Serialization.JsonIgnoreCondition.Never", _ => null }; - + /// Gets the json property required. public string JsonPropertyRequiredCode {