diff --git a/src/NJsonSchema.NewtonsoftJson/Generation/NewtonsoftJsonReflectionService.cs b/src/NJsonSchema.NewtonsoftJson/Generation/NewtonsoftJsonReflectionService.cs index 8a729195b..3177cd40b 100644 --- a/src/NJsonSchema.NewtonsoftJson/Generation/NewtonsoftJsonReflectionService.cs +++ b/src/NJsonSchema.NewtonsoftJson/Generation/NewtonsoftJsonReflectionService.cs @@ -171,14 +171,16 @@ private void LoadPropertyOrField(JsonProperty jsonProperty, ContextualAccessorIn } } - var requiredAttribute = accessorInfo - .GetAttributes(true) + var attributes = accessorInfo.GetAttributes(true); + var requiredAttribute = attributes .FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.RequiredAttribute"); + var hasRequiredMemberAttribute = attributes.FirstAssignableToTypeNameOrDefault( + "System.Runtime.CompilerServices.RequiredMemberAttribute") != null; var hasJsonNetAttributeRequired = jsonProperty.Required is Required.Always or Required.AllowNull; var isDataContractMemberRequired = schemaGenerator.GetDataMemberAttribute(accessorInfo, parentType)?.IsRequired == true; - var hasRequiredAttribute = requiredAttribute != null; + var hasRequiredAttribute = requiredAttribute != null || hasRequiredMemberAttribute; if (hasRequiredAttribute || isDataContractMemberRequired || hasJsonNetAttributeRequired) { parentSchema.RequiredProperties.Add(propertyName); diff --git a/src/NJsonSchema.Tests/Generation/AttributeGenerationTests.cs b/src/NJsonSchema.Tests/Generation/AttributeGenerationTests.cs index a3dc11d84..e324870a4 100644 --- a/src/NJsonSchema.Tests/Generation/AttributeGenerationTests.cs +++ b/src/NJsonSchema.Tests/Generation/AttributeGenerationTests.cs @@ -335,5 +335,24 @@ public void When_required_DateTime_then_MinLength_is_not_set() #endif Assert.Equal(1, schema.Properties["RequiredString"].MinLength); } + +#if NET7_0_OR_GREATER + public class ClassWithRequiredKeyword + { + public required string Name { get; set; } + public string Optional { get; set; } + } + + [Fact] + public void When_property_has_required_keyword_then_it_is_required_in_Newtonsoft_schema() + { + // Act + var schema = NewtonsoftJsonSchemaGenerator.FromType(); + + // Assert + Assert.Contains("Name", schema.RequiredProperties); + Assert.DoesNotContain("Optional", schema.RequiredProperties); + } +#endif } } \ No newline at end of file diff --git a/src/NJsonSchema.Tests/Generation/SystemTextJson/SystemTextJsonTests.cs b/src/NJsonSchema.Tests/Generation/SystemTextJson/SystemTextJsonTests.cs index eeb64fdd4..5249a4aaa 100644 --- a/src/NJsonSchema.Tests/Generation/SystemTextJson/SystemTextJsonTests.cs +++ b/src/NJsonSchema.Tests/Generation/SystemTextJson/SystemTextJsonTests.cs @@ -132,5 +132,42 @@ public void When_JsonPropertyOrder_is_set_then_properties_are_sorted_in_schema() Assert.Equal("A", keys[1]); // order 1 Assert.Equal("B", keys[2]); // order 2 } + +#if NET7_0_OR_GREATER + public class ClassWithRequiredKeyword + { + public required string Name { get; set; } + public string Optional { get; set; } + } + + [Fact] + public void When_property_has_required_keyword_then_it_is_required_in_schema() + { + // Act + var schema = JsonSchema.FromType(); + + // Assert + Assert.Contains("Name", schema.RequiredProperties); + Assert.DoesNotContain("Optional", schema.RequiredProperties); + } + + public class ClassWithJsonRequired + { + [System.Text.Json.Serialization.JsonRequired] + public string Name { get; set; } + public string Optional { get; set; } + } + + [Fact] + public void When_property_has_JsonRequired_then_it_is_required_in_schema() + { + // Act + var schema = JsonSchema.FromType(); + + // Assert + Assert.Contains("Name", schema.RequiredProperties); + Assert.DoesNotContain("Optional", schema.RequiredProperties); + } +#endif } } diff --git a/src/NJsonSchema/Generation/JsonSchemaGenerator.cs b/src/NJsonSchema/Generation/JsonSchemaGenerator.cs index 7392fa81a..25559c7e5 100644 --- a/src/NJsonSchema/Generation/JsonSchemaGenerator.cs +++ b/src/NJsonSchema/Generation/JsonSchemaGenerator.cs @@ -1205,7 +1205,7 @@ public void AddProperty( if (hasRequiredAttribute && !propertyTypeDescription.IsEnum && propertyTypeDescription.Type == JsonObjectType.String && - !requiredAttribute.TryGetPropertyValue("AllowEmptyStrings", false) && + (requiredAttribute == null || !requiredAttribute.TryGetPropertyValue("AllowEmptyStrings", false)) && !IsDateTimeFormat(propertyTypeDescription.Format)) { propertySchema.MinLength = 1; diff --git a/src/NJsonSchema/Generation/SystemTextJsonReflectionService.cs b/src/NJsonSchema/Generation/SystemTextJsonReflectionService.cs index c6e32839a..571f2adfd 100644 --- a/src/NJsonSchema/Generation/SystemTextJsonReflectionService.cs +++ b/src/NJsonSchema/Generation/SystemTextJsonReflectionService.cs @@ -88,10 +88,14 @@ public override void GenerateProperties(JsonSchema schema, ContextualType contex } var requiredAttribute = attributes.FirstAssignableToTypeNameOrDefault("System.ComponentModel.DataAnnotations.RequiredAttribute"); + var hasRequiredMemberAttribute = attributes.FirstAssignableToTypeNameOrDefault( + "System.Runtime.CompilerServices.RequiredMemberAttribute") != null; + var hasJsonRequiredAttribute = attributes.FirstAssignableToTypeNameOrDefault( + "System.Text.Json.Serialization.JsonRequiredAttribute") != null; var isDataContractMemberRequired = schemaGenerator.GetDataMemberAttribute(accessorInfo, contextualType.Type)?.IsRequired == true; - var hasRequiredAttribute = requiredAttribute != null; + var hasRequiredAttribute = requiredAttribute != null || hasRequiredMemberAttribute || hasJsonRequiredAttribute; if (hasRequiredAttribute || isDataContractMemberRequired) { schema.RequiredProperties.Add(propertyName);