diff --git a/src/Swashbuckle.AspNetCore.Newtonsoft/SchemaGenerator/JsonPropertyExtensions.cs b/src/Swashbuckle.AspNetCore.Newtonsoft/SchemaGenerator/JsonPropertyExtensions.cs index 1799376f30..f3fdab3085 100644 --- a/src/Swashbuckle.AspNetCore.Newtonsoft/SchemaGenerator/JsonPropertyExtensions.cs +++ b/src/Swashbuckle.AspNetCore.Newtonsoft/SchemaGenerator/JsonPropertyExtensions.cs @@ -17,16 +17,7 @@ public static bool TryGetMemberInfo(this JsonProperty jsonProperty, out MemberIn public static bool IsRequiredSpecified(this JsonProperty jsonProperty) { - if (!jsonProperty.TryGetMemberInfo(out MemberInfo memberInfo)) - return false; - - if (memberInfo.GetCustomAttribute() != null) - return true; - - var jsonPropertyAttributeData = memberInfo.GetCustomAttributesData() - .FirstOrDefault(attrData => attrData.AttributeType == typeof(JsonPropertyAttribute)); - - return (jsonPropertyAttributeData != null) && jsonPropertyAttributeData.NamedArguments.Any(arg => arg.MemberName == "Required"); + return jsonProperty.Required != Required.Default; } } } diff --git a/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/DataMemberAnnotatedType.cs b/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/DataMemberAnnotatedType.cs new file mode 100644 index 0000000000..b8b6ea3303 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/DataMemberAnnotatedType.cs @@ -0,0 +1,20 @@ +using System.Runtime.Serialization; + +namespace Swashbuckle.AspNetCore.Newtonsoft.Test +{ + [DataContract(Name = "CustomNameFromDataContract")] + public class DataMemberAnnotatedType + { + [DataMember(IsRequired = true)] + public string StringWithDataMemberRequired { get; set; } + + [DataMember(IsRequired = false)] + public string StringWithDataMemberNonRequired { get; set; } + + [DataMember(IsRequired = true, Name = "RequiredWithCustomNameFromDataMember")] + public string StringWithDataMemberRequiredWithCustomName { get; set; } + + [DataMember(IsRequired = false, Name = "NonRequiredWithCustomNameFromDataMember")] + public string StringWithDataMemberNonRequiredWithCustomName { get; set; } + } +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/JsonObjectAnnotatedType.cs b/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/JsonObjectAnnotatedType.cs index c3385cb49d..24d1ba005c 100644 --- a/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/JsonObjectAnnotatedType.cs +++ b/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/JsonObjectAnnotatedType.cs @@ -1,8 +1,10 @@ -using Newtonsoft.Json; +using System.Runtime.Serialization; +using Newtonsoft.Json; namespace Swashbuckle.AspNetCore.Newtonsoft.Test { [JsonObject(ItemRequired = Required.Always)] + [DataContract] public class JsonObjectAnnotatedType { public string StringWithNoAnnotation { get; set; } @@ -12,5 +14,8 @@ public class JsonObjectAnnotatedType [JsonProperty(Required = Required.AllowNull)] public string StringWithRequiredAllowNull { get; set; } + + [DataMember(IsRequired = false)] + public string StringWithDataMemberRequiredFalse { get; set; } } } diff --git a/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/JsonPropertyAnnotatedType.cs b/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/JsonPropertyAnnotatedType.cs index c50f2bbee0..92992191f2 100644 --- a/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/JsonPropertyAnnotatedType.cs +++ b/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/JsonPropertyAnnotatedType.cs @@ -1,7 +1,9 @@ -using Newtonsoft.Json; +using System.Runtime.Serialization; +using Newtonsoft.Json; namespace Swashbuckle.AspNetCore.Newtonsoft.Test { + [DataContract] public class JsonPropertyAnnotatedType { [JsonProperty("string-with-json-property-name")] @@ -21,5 +23,13 @@ public class JsonPropertyAnnotatedType [JsonProperty(Required = Required.AllowNull)] public string StringWithRequiredAllowNull { get; set; } + + [DataMember(IsRequired = false)] //As the support for DataMember has been implemented later, JsonProperty.Required should take precedence + [JsonProperty(Required = Required.Always)] + public string StringWithRequiredAlwaysButConflictingDataMember { get; set; } + + [DataMember(IsRequired = true)] //As the support for DataMember has been implemented later, JsonProperty.Required should take precedence + [JsonProperty(Required = Required.Default)] + public string StringWithRequiredDefaultButConflictingDataMember { get; set; } } -} \ No newline at end of file +} diff --git a/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/JsonRequiredAnnotatedType.cs b/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/JsonRequiredAnnotatedType.cs index 1709b237f6..ad4584cda4 100644 --- a/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/JsonRequiredAnnotatedType.cs +++ b/test/Swashbuckle.AspNetCore.Newtonsoft.Test/Fixtures/JsonRequiredAnnotatedType.cs @@ -1,10 +1,16 @@ -using Newtonsoft.Json; +using System.Runtime.Serialization; +using Newtonsoft.Json; namespace Swashbuckle.AspNetCore.Newtonsoft.Test { + [DataContract] public class JsonRequiredAnnotatedType { [JsonRequired] public string StringWithJsonRequired { get; set; } + + [DataMember(IsRequired = false)] //As the support for DataMember has been implemented later, JsonRequired should take precedence + [JsonRequired] + public string StringWithConflictingRequired { get; set; } } } \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.Newtonsoft.Test/SchemaGenerator/NewtonsoftSchemaGeneratorTests.cs b/test/Swashbuckle.AspNetCore.Newtonsoft.Test/SchemaGenerator/NewtonsoftSchemaGeneratorTests.cs index ed2b4b9612..b69b3b81a6 100644 --- a/test/Swashbuckle.AspNetCore.Newtonsoft.Test/SchemaGenerator/NewtonsoftSchemaGeneratorTests.cs +++ b/test/Swashbuckle.AspNetCore.Newtonsoft.Test/SchemaGenerator/NewtonsoftSchemaGeneratorTests.cs @@ -755,6 +755,8 @@ public void GenerateSchema_HonorsSerializerAttribute_JsonProperty() "StringWithRequiredDisallowNull", "StringWithRequiredAlways", "StringWithRequiredAllowNull", + "StringWithRequiredAlwaysButConflictingDataMember", + "StringWithRequiredDefaultButConflictingDataMember" }, schema.Properties.Keys.ToArray() ); @@ -762,7 +764,8 @@ public void GenerateSchema_HonorsSerializerAttribute_JsonProperty() new[] { "StringWithRequiredAllowNull", - "StringWithRequiredAlways" + "StringWithRequiredAlways", + "StringWithRequiredAlwaysButConflictingDataMember" }, schema.Required.ToArray() ); @@ -772,6 +775,8 @@ public void GenerateSchema_HonorsSerializerAttribute_JsonProperty() Assert.False(schema.Properties["StringWithRequiredDisallowNull"].Nullable); Assert.False(schema.Properties["StringWithRequiredAlways"].Nullable); Assert.True(schema.Properties["StringWithRequiredAllowNull"].Nullable); + Assert.False(schema.Properties["StringWithRequiredAlwaysButConflictingDataMember"].Nullable); + Assert.True(schema.Properties["StringWithRequiredDefaultButConflictingDataMember"].Nullable); } [Fact] @@ -782,7 +787,7 @@ public void GenerateSchema_HonorsSerializerAttribute_JsonRequired() var referenceSchema = Subject().GenerateSchema(typeof(JsonRequiredAnnotatedType), schemaRepository); var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; - Assert.Equal(new[] { "StringWithJsonRequired" }, schema.Required.ToArray()); + Assert.Equal(new[] { "StringWithConflictingRequired", "StringWithJsonRequired"}, schema.Required.ToArray()); Assert.False(schema.Properties["StringWithJsonRequired"].Nullable); } @@ -797,6 +802,7 @@ public void GenerateSchema_HonorsSerializerAttribute_JsonObject() Assert.Equal( new[] { + "StringWithDataMemberRequiredFalse", "StringWithNoAnnotation", "StringWithRequiredAllowNull", "StringWithRequiredUnspecified" @@ -806,6 +812,7 @@ public void GenerateSchema_HonorsSerializerAttribute_JsonObject() Assert.False(schema.Properties["StringWithNoAnnotation"].Nullable); Assert.False(schema.Properties["StringWithRequiredUnspecified"].Nullable); Assert.True(schema.Properties["StringWithRequiredAllowNull"].Nullable); + Assert.False(schema.Properties["StringWithDataMemberRequiredFalse"].Nullable); } [Fact] @@ -821,6 +828,43 @@ public void GenerateSchema_HonorsSerializerAttribute_JsonExtensionData() Assert.Null(schema.AdditionalProperties.Type); } + [Fact] + public void GenerateSchema_HonorsDataMemberAttribute() + { + var schemaRepository = new SchemaRepository(); + + var referenceSchema = Subject().GenerateSchema(typeof(DataMemberAnnotatedType), schemaRepository); + + var schema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + + + Assert.True(schema.Properties["StringWithDataMemberRequired"].Nullable); + Assert.True(schema.Properties["StringWithDataMemberNonRequired"].Nullable); + Assert.True(schema.Properties["RequiredWithCustomNameFromDataMember"].Nullable); + Assert.True(schema.Properties["NonRequiredWithCustomNameFromDataMember"].Nullable); + + Assert.Equal( + new[] + { + + "StringWithDataMemberRequired", + "StringWithDataMemberNonRequired", + "RequiredWithCustomNameFromDataMember", + "NonRequiredWithCustomNameFromDataMember" + }, + schema.Properties.Keys.ToArray() + ); + + Assert.Equal( + new[] + { + "RequiredWithCustomNameFromDataMember", + "StringWithDataMemberRequired" + }, + schema.Required.ToArray() + ); + } + [Theory] [InlineData(typeof(ProblemDetails))] [InlineData(typeof(ValidationProblemDetails))]