From a99c2aaa942813c3202a26e806b6460546205cc7 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 21 Jul 2021 18:56:20 +0800 Subject: [PATCH 1/3] Supports nested ExtensibleObject classes. Resolve #9581 --- .../AbpHasExtraPropertiesJsonConverter.cs | 1 + ...pHasExtraPropertiesJsonConverterFactory.cs | 13 ++++ ...bpHasExtraPropertiesJsonConverter_Tests.cs | 60 +++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHasExtraPropertiesJsonConverter_Tests.cs diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs index 47640ec306..06cf0ae040 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs @@ -15,6 +15,7 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters x == this || x.GetType() == typeof(AbpHasExtraPropertiesJsonConverterFactory)); + newOptions.Converters.Add(new AbpHasExtraPropertiesJsonConverterFactory(typeToConvert)); var rootElement = JsonDocument.ParseValue(ref reader).RootElement; if (rootElement.ValueKind == JsonValueKind.Object) { diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs index f654504e05..0bc9cef11e 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; @@ -11,8 +12,20 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters { private static readonly ConcurrentDictionary CachedTypes = new ConcurrentDictionary(); + private static readonly List ExcludeTypes = new List(); + + public AbpHasExtraPropertiesJsonConverterFactory(params Type[] excludeTypes) + { + ExcludeTypes.AddIfNotContains(excludeTypes); + } + public override bool CanConvert(Type typeToConvert) { + if (ExcludeTypes.Contains(typeToConvert)) + { + return false; + } + //Only for private or protected ExtraProperties. if (typeof(IHasExtraProperties).IsAssignableFrom(typeToConvert)) { diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHasExtraPropertiesJsonConverter_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHasExtraPropertiesJsonConverter_Tests.cs new file mode 100644 index 0000000000..b80380086d --- /dev/null +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHasExtraPropertiesJsonConverter_Tests.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using System.Linq; +using Shouldly; +using Volo.Abp.Data; +using Volo.Abp.ObjectExtending; +using Xunit; + +namespace Volo.Abp.Json +{ + public class AbpHasExtraPropertiesJsonConverter_Tests: AbpJsonTestBase + { + private readonly IJsonSerializer _jsonSerializer; + + public AbpHasExtraPropertiesJsonConverter_Tests() + { + _jsonSerializer = GetRequiredService(); + } + + [Fact] + public void JsonConverter_Test() + { + var fooDto = new FooDto + { + Name = "foo-dto", + BarDtos = new List() + }; + fooDto.SetProperty("foo", "foo-value"); + + var barDto = new BarDto + { + Name = "bar-dto" + }; + barDto.SetProperty("bar", "bar-value"); + fooDto.BarDtos.Add(barDto); + + var json = _jsonSerializer.Serialize(fooDto); + + fooDto = _jsonSerializer.Deserialize(json); + fooDto.ShouldNotBeNull(); + fooDto.Name.ShouldBe("foo-dto"); + fooDto.GetProperty("foo").ShouldBe("foo-value"); + + fooDto.BarDtos.Count.ShouldBe(1); + fooDto.BarDtos.First().Name.ShouldBe("bar-dto"); + fooDto.BarDtos.First().GetProperty("bar").ShouldBe("bar-value"); + } + } + + public class FooDto : ExtensibleObject + { + public string Name { get; set; } + + public List BarDtos { get; set; } + } + + public class BarDto : ExtensibleObject + { + public string Name { get; set; } + } +} From f59abe5aa0aff10351e23808b9fd60d2444fc167 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 21 Jul 2021 22:07:20 +0800 Subject: [PATCH 2/3] Use non-static to store excluded types. --- .../AbpHasExtraPropertiesJsonConverter.cs | 20 +++++++++++++++---- ...pHasExtraPropertiesJsonConverterFactory.cs | 15 ++++++++++---- ...bpHasExtraPropertiesJsonConverter_Tests.cs | 16 +++++++++++++++ 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs index 06cf0ae040..fa1a4f4fcf 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs @@ -11,11 +11,23 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters { public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - var newOptions = JsonSerializerOptionsHelper.Create(options, x => - x == this || - x.GetType() == typeof(AbpHasExtraPropertiesJsonConverterFactory)); + var newOptions = JsonSerializerOptionsHelper.Create(options, x => x == this); + + var converterFactory = newOptions.Converters.FirstOrDefault(x => x is AbpHasExtraPropertiesJsonConverterFactory).As(); + var newConverterFactory = new AbpHasExtraPropertiesJsonConverterFactory(); + if (converterFactory != null) + { + newOptions.Converters.Remove(converterFactory); + newConverterFactory.AddExcludeTypes(converterFactory.GetExcludeTypes().ToArray()); + } + else + { + newConverterFactory.AddExcludeTypes(typeToConvert); + } + + newConverterFactory.AddExcludeTypes(typeToConvert); + newOptions.Converters.Add(newConverterFactory); - newOptions.Converters.Add(new AbpHasExtraPropertiesJsonConverterFactory(typeToConvert)); var rootElement = JsonDocument.ParseValue(ref reader).RootElement; if (rootElement.ValueKind == JsonValueKind.Object) { diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs index 0bc9cef11e..dff25e00df 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Collections.Immutable; using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; @@ -12,16 +13,22 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters { private static readonly ConcurrentDictionary CachedTypes = new ConcurrentDictionary(); - private static readonly List ExcludeTypes = new List(); + private readonly List _excludeTypes = new List(); - public AbpHasExtraPropertiesJsonConverterFactory(params Type[] excludeTypes) + public virtual AbpHasExtraPropertiesJsonConverterFactory AddExcludeTypes(params Type[] excludeTypes) { - ExcludeTypes.AddIfNotContains(excludeTypes); + _excludeTypes.AddIfNotContains(excludeTypes); + return this; + } + + public virtual IReadOnlyList GetExcludeTypes() + { + return _excludeTypes.ToImmutableList(); } public override bool CanConvert(Type typeToConvert) { - if (ExcludeTypes.Contains(typeToConvert)) + if (_excludeTypes.Contains(typeToConvert)) { return false; } diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHasExtraPropertiesJsonConverter_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHasExtraPropertiesJsonConverter_Tests.cs index b80380086d..c11e8f3cec 100644 --- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHasExtraPropertiesJsonConverter_Tests.cs +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHasExtraPropertiesJsonConverter_Tests.cs @@ -43,6 +43,22 @@ namespace Volo.Abp.Json fooDto.BarDtos.Count.ShouldBe(1); fooDto.BarDtos.First().Name.ShouldBe("bar-dto"); fooDto.BarDtos.First().GetProperty("bar").ShouldBe("bar-value"); + + fooDto.Name = "new-foo-dto"; + fooDto.SetProperty("foo", "new-foo-value"); + fooDto.BarDtos.First().Name = "new-bar-dto"; + fooDto.BarDtos.First().SetProperty("bar", "new-bar-value"); + + json = _jsonSerializer.Serialize(fooDto); + + fooDto = _jsonSerializer.Deserialize(json); + fooDto.ShouldNotBeNull(); + fooDto.Name.ShouldBe("new-foo-dto"); + fooDto.GetProperty("foo").ShouldBe("new-foo-value"); + + fooDto.BarDtos.Count.ShouldBe(1); + fooDto.BarDtos.First().Name.ShouldBe("new-bar-dto"); + fooDto.BarDtos.First().GetProperty("bar").ShouldBe("new-bar-value"); } } From 9604e4d55cc46cbb053e18753711f9740440156f Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 21 Jul 2021 22:09:30 +0800 Subject: [PATCH 3/3] Remove unnecessary code --- .../JsonConverters/AbpHasExtraPropertiesJsonConverter.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs index fa1a4f4fcf..ebd561c0ae 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs @@ -20,10 +20,6 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters newOptions.Converters.Remove(converterFactory); newConverterFactory.AddExcludeTypes(converterFactory.GetExcludeTypes().ToArray()); } - else - { - newConverterFactory.AddExcludeTypes(typeToConvert); - } newConverterFactory.AddExcludeTypes(typeToConvert); newOptions.Converters.Add(newConverterFactory);