Skip to content

Commit

Permalink
Generate STJ JsonIgnoreAttributes for model properties (RicoSuter#1513)
Browse files Browse the repository at this point in the history
* Generate STJ JsonIgnoreAttributes for model properties

* Update PropertyModel.cs

Co-authored-by: Rico Suter <[email protected]>
  • Loading branch information
jcracknell and RicoSuter authored May 8, 2022
1 parent 0dd030d commit fca4d1f
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 1 deletion.
126 changes: 126 additions & 0 deletions src/NJsonSchema.CodeGeneration.CSharp.Tests/GeneralGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,132 @@ 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()
Expand Down
12 changes: 11 additions & 1 deletion src/NJsonSchema.CodeGeneration.CSharp/Models/PropertyModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,17 @@ public PropertyModel(
(_property.ActualTypeSchema.IsArray && _settings.GenerateImmutableArrayProperties) ||
(_property.ActualTypeSchema.IsDictionary && _settings.GenerateImmutableDictionaryProperties)
)) == false;


/// <summary>Indicates whether or not this property has a <see cref="JsonIgnoreCondition"/>.</summary>
public bool HasJsonIgnoreCondition => JsonIgnoreCondition != null;

/// <summary>Returns the System.Text.Json.Serialization.JsonIgnoreCondition value to be applied to the property.</summary>
public string JsonIgnoreCondition => _property switch {
{ IsRequired: false } => "System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull",
{ IsRequired: true } when _settings.RequiredPropertiesMustBeDefined => "System.Text.Json.Serialization.JsonIgnoreCondition.Never",
_ => null
};

/// <summary>Gets the json property required.</summary>
public string JsonPropertyRequiredCode
{
Expand Down
3 changes: 3 additions & 0 deletions src/NJsonSchema.CodeGeneration.CSharp/Templates/Class.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
{%- endif -%}
{%- if UseSystemTextJson %}
[System.Text.Json.Serialization.JsonPropertyName("{{ property.Name }}")]
{%- if property.HasJsonIgnoreCondition %}
[System.Text.Json.Serialization.JsonIgnore(Condition = {{ property.JsonIgnoreCondition }})]
{%- endif -%}
{%- if property.IsStringEnumArray %}
// TODO(system.text.json): Add string enum item converter
{%- endif -%}
Expand Down

0 comments on commit fca4d1f

Please sign in to comment.