diff --git a/src/libraries/System.Text.Json/gen/Reflection/RoslynExtensions.cs b/src/libraries/System.Text.Json/gen/Reflection/RoslynExtensions.cs index aa3f431fced8d0..a1f7eb6cdd2380 100644 --- a/src/libraries/System.Text.Json/gen/Reflection/RoslynExtensions.cs +++ b/src/libraries/System.Text.Json/gen/Reflection/RoslynExtensions.cs @@ -37,7 +37,7 @@ public static MethodAttributes GetMethodAttributes(this IMethodSymbol methodSymb if (methodSymbol.IsAbstract) { - attributes |= MethodAttributes.Abstract; + attributes |= MethodAttributes.Abstract | MethodAttributes.Virtual; } if (methodSymbol.IsStatic) diff --git a/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.cs b/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.cs index 32189f4beb462b..a2b5845ca44dca 100644 --- a/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.cs +++ b/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.cs @@ -2653,5 +2653,94 @@ public async Task JsonIgnoreCondition_WhenWritingDefault_OnInterface() json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal("{\"MyProp\":{}}", json); } + + public class ConcreteDerivedClass : AbstractBaseClass + { + // Ignored including on base class: + [JsonIgnore] public override int Abstract_Ignored_Property { get; set; } + [JsonIgnore] public override int Virtual_Ignored_Property { get; set; } + + // Ignored but not specified on base class: + [JsonIgnore] public override int Abstract_IgnoredOnConcrete_Property { get; set; } + [JsonIgnore] public override int Virtual_IgnoredOnConcrete_Property { get; set; } + + // Ignored specified on base class: + [JsonPropertyOrder(1)] public override int Abstract_IgnoredOnBase_Property { get; set; } + [JsonPropertyOrder(2)] public override int Virtual_IgnoredOnBase_Property { get; set; } + + // Standard overrides (not ignored): + [JsonPropertyOrder(3)] public override int Abstract_Property { get; set; } + [JsonPropertyOrder(4)] public override int Virtual_Property { get; set; } + } + + public abstract class AbstractBaseClass + { + [JsonIgnore] public abstract int Abstract_Ignored_Property { get; set; } + [JsonIgnore] public virtual int Virtual_Ignored_Property { get; set; } + + public abstract int Abstract_IgnoredOnConcrete_Property { get; set; } + public virtual int Virtual_IgnoredOnConcrete_Property { get; set; } + + [JsonIgnore] public abstract int Abstract_IgnoredOnBase_Property { get; set; } + [JsonIgnore] public virtual int Virtual_IgnoredOnBase_Property { get; set; } + + public abstract int Abstract_Property { get; set; } + public virtual int Virtual_Property { get; set; } + } + + [Fact] + public async Task JsonIgnoreCondition_Polymorphic() + { + ConcreteDerivedClass obj = new() + { + Abstract_Ignored_Property = -1, + Virtual_Ignored_Property = -1, + Abstract_IgnoredOnConcrete_Property = -1, + Virtual_IgnoredOnConcrete_Property = -1, + Abstract_IgnoredOnBase_Property = 1, + Virtual_IgnoredOnBase_Property = 2, + Abstract_Property = 3, + Virtual_Property = 4, + }; + + // Verify properties work as expected. + Assert.Equal(-1, obj.Abstract_Ignored_Property); + Assert.Equal(-1, obj.Virtual_Ignored_Property); + Assert.Equal(-1, obj.Abstract_IgnoredOnConcrete_Property); + Assert.Equal(-1, obj.Virtual_IgnoredOnConcrete_Property); + Assert.Equal(1, obj.Abstract_IgnoredOnBase_Property); + Assert.Equal(2, obj.Virtual_IgnoredOnBase_Property); + Assert.Equal(3, obj.Abstract_Property); + Assert.Equal(4, obj.Virtual_Property); + + const string ExpectedJson = "{" + + "\"Abstract_IgnoredOnBase_Property\":1," + + "\"Virtual_IgnoredOnBase_Property\":2," + + "\"Abstract_Property\":3," + + "\"Virtual_Property\":4}"; + + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); + Assert.Equal(ExpectedJson, json); + + const string Json = "{" + + "\"Abstract_Ignored_Property\":-1," + + "\"Virtual_Ignored_Property\":-1," + + "\"Abstract_IgnoredOnConcrete_Property\":-1," + + "\"Virtual_IgnoredOnConcrete_Property\":-1," + + "\"Abstract_IgnoredOnBase_Property\":1," + + "\"Virtual_IgnoredOnBase_Property\":2," + + "\"Abstract_Property\":3," + + "\"Virtual_Property\":4}"; + + obj = await JsonSerializerWrapperForString.DeserializeWrapper(Json); + Assert.Equal(0, obj.Abstract_Ignored_Property); + Assert.Equal(0, obj.Virtual_Ignored_Property); + Assert.Equal(0, obj.Abstract_IgnoredOnConcrete_Property); + Assert.Equal(0, obj.Virtual_IgnoredOnConcrete_Property); + Assert.Equal(1, obj.Abstract_IgnoredOnBase_Property); + Assert.Equal(2, obj.Virtual_IgnoredOnBase_Property); + Assert.Equal(3, obj.Abstract_Property); + Assert.Equal(4, obj.Virtual_Property); + } } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs index 8b2243fd835c22..f4858804d60123 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs @@ -263,6 +263,7 @@ public override async Task HonorJsonPropertyName_PrivateSetter() [JsonSerializable(typeof(StructWithPropertiesWithJsonPropertyName_PrivateSetter))] [JsonSerializable(typeof(ClassWithValueAndReferenceTypes))] [JsonSerializable(typeof(ClassWithReadOnlyStringProperty_IgnoreWhenWritingDefault))] + [JsonSerializable(typeof(ConcreteDerivedClass))] internal sealed partial class PropertyVisibilityTestsContext_Metadata : JsonSerializerContext { } @@ -429,6 +430,7 @@ public override async Task JsonIgnoreCondition_WhenWritingNull_OnValueType_Fail_ [JsonSerializable(typeof(StructWithPropertiesWithJsonPropertyName_PrivateSetter))] [JsonSerializable(typeof(ClassWithValueAndReferenceTypes))] [JsonSerializable(typeof(ClassWithReadOnlyStringProperty_IgnoreWhenWritingDefault))] + [JsonSerializable(typeof(ConcreteDerivedClass))] internal sealed partial class PropertyVisibilityTestsContext_Default : JsonSerializerContext { }