From dfe75c2a1d32846c7d830c96184403b5e430b488 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 1 Dec 2021 11:00:46 +0800 Subject: [PATCH] Add `JsonInclude` to `ExtensibleObject ` & Remove `AbpHasExtraPropertiesJsonConverter`. --- .../Mvc/Json/AbpJsonOptionsSetup.cs | 1 - ...AbpSystemTextJsonSerializerOptionsSetup.cs | 1 - .../AbpHasExtraPropertiesJsonConverter.cs | 56 ---------------- ...pHasExtraPropertiesJsonConverterFactory.cs | 65 ------------------- .../Abp/ObjectExtending/ExtensibleObject.cs | 2 + ...pSystemTextJsonSerializerProvider_Tests.cs | 3 +- ...ter_Tests.cs => ExtensibleObject_Tests.cs} | 45 +++++++++++-- 7 files changed, 44 insertions(+), 129 deletions(-) delete mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs delete mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs rename framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/{AbpHasExtraPropertiesJsonConverter_Tests.cs => ExtensibleObject_Tests.cs} (62%) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs index 43a9c04d32..077578413b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs @@ -29,7 +29,6 @@ namespace Volo.Abp.AspNetCore.Mvc.Json options.JsonSerializerOptions.Converters.Add(new AbpStringToBooleanConverter()); options.JsonSerializerOptions.Converters.Add(new ObjectToInferredTypesConverter()); - options.JsonSerializerOptions.Converters.Add(new AbpHasExtraPropertiesJsonConverterFactory()); } } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs index 3c6357c92e..98b7fdbcb1 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs @@ -25,7 +25,6 @@ namespace Volo.Abp.Json.SystemTextJson options.JsonSerializerOptions.Converters.Add(new AbpStringToBooleanConverter()); options.JsonSerializerOptions.Converters.Add(new ObjectToInferredTypesConverter()); - options.JsonSerializerOptions.Converters.Add(new AbpHasExtraPropertiesJsonConverterFactory()); // If the user hasn't explicitly configured the encoder, use the less strict encoder that does not encode all non-ASCII characters. options.JsonSerializerOptions.Encoder ??= JavaScriptEncoder.UnsafeRelaxedJsonEscaping; 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 deleted file mode 100644 index 5b2eb5a15a..0000000000 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Linq; -using System.Text.Json; -using System.Text.Json.Serialization; -using Volo.Abp.Data; - -namespace Volo.Abp.Json.SystemTextJson.JsonConverters -{ - public class AbpHasExtraPropertiesJsonConverter : JsonConverter - where T : IHasExtraProperties - { - private JsonSerializerOptions _readJsonSerializerOptions; - - private JsonSerializerOptions _writeJsonSerializerOptions; - - public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - _readJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, x => x == this); - - var rootElement = JsonDocument.ParseValue(ref reader).RootElement; - if (rootElement.ValueKind == JsonValueKind.Object) - { - var converterFactory = _readJsonSerializerOptions.Converters - .FirstOrDefault(x => x is AbpHasExtraPropertiesJsonConverterFactory) - .As(); - - T extensibleObject; - using (converterFactory != null ? converterFactory.Exclude(typeToConvert) : NullDisposable.Instance) - { - extensibleObject = rootElement.Deserialize(_readJsonSerializerOptions); - } - - var extraPropertiesJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IHasExtraProperties.ExtraProperties), StringComparison.OrdinalIgnoreCase)); - - if (extraPropertiesJsonProperty.Value.ValueKind == JsonValueKind.Object) - { - var extraPropertyDictionary = extraPropertiesJsonProperty.Value.Deserialize(typeof(ExtraPropertyDictionary), _readJsonSerializerOptions); - ObjectHelper.TrySetProperty(extensibleObject, x => x.ExtraProperties, () => extraPropertyDictionary); - } - - return extensibleObject; - } - - throw new JsonException("RootElement's ValueKind is not Object!"); - } - - public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) - { - _writeJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, x => - x == this || - x.GetType() == typeof(AbpHasExtraPropertiesJsonConverterFactory)); - - JsonSerializer.Serialize(writer, value, _writeJsonSerializerOptions); - } - } -} 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 deleted file mode 100644 index e0d99bf8cb..0000000000 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text.Json; -using System.Text.Json.Serialization; -using System.Threading; -using Volo.Abp.Data; - -namespace Volo.Abp.Json.SystemTextJson.JsonConverters -{ - public class AbpHasExtraPropertiesJsonConverterFactory : JsonConverterFactory - { - private static readonly ConcurrentDictionary CachedTypes = new ConcurrentDictionary(); - - private readonly AsyncLocal> _excludeTypes = new AsyncLocal>(); - - public IDisposable Exclude(params Type[] excludeTypes) - { - var parent = _excludeTypes.Value; - _excludeTypes.Value = excludeTypes.ToList(); - return new DisposeAction(() => - { - _excludeTypes.Value = parent; - }); - } - - public override bool CanConvert(Type typeToConvert) - { - if (_excludeTypes.Value != null && _excludeTypes.Value.Contains(typeToConvert)) - { - return false; - } - - //Only for private or protected ExtraProperties. - if (typeof(IHasExtraProperties).IsAssignableFrom(typeToConvert)) - { - return CachedTypes.GetOrAdd(typeToConvert, type => - { - var property = type.GetProperty(nameof(IHasExtraProperties.ExtraProperties)); - if (property != null) - { - var setMethod = property.GetSetMethod(true); - return setMethod != null && (setMethod.IsPrivate || setMethod.IsFamily); - } - - return false; - }); - } - - return false; - } - - public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) - { - return (JsonConverter) Activator.CreateInstance( - typeof(AbpHasExtraPropertiesJsonConverter<>).MakeGenericType(typeToConvert), - BindingFlags.Instance | BindingFlags.Public, - binder: null, - null, - culture: null)!; - } - } -} diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObject.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObject.cs index d068015581..1e87049ed7 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObject.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObject.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using Volo.Abp.Data; using Volo.Abp.DynamicProxy; @@ -9,6 +10,7 @@ namespace Volo.Abp.ObjectExtending [Serializable] public class ExtensibleObject : IHasExtraProperties, IValidatableObject { + [JsonInclude] public ExtraPropertyDictionary ExtraProperties { get; protected set; } public ExtensibleObject() diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs index 3f7ce5dc26..3ceca6a2c2 100644 --- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs @@ -174,8 +174,7 @@ namespace Volo.Abp.Json { var json = "{\"name\":\"test\",\"extraProperties\":null}"; var extensibleObject = JsonSerializer.Deserialize(json); - extensibleObject.ExtraProperties.ShouldNotBeNull(); - extensibleObject.ExtraProperties.ShouldBeEmpty(); + extensibleObject.ExtraProperties.ShouldBeNull(); } [Fact] 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/ExtensibleObject_Tests.cs similarity index 62% rename from framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHasExtraPropertiesJsonConverter_Tests.cs rename to framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ExtensibleObject_Tests.cs index c11e8f3cec..f3c6095922 100644 --- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHasExtraPropertiesJsonConverter_Tests.cs +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ExtensibleObject_Tests.cs @@ -7,11 +7,11 @@ using Xunit; namespace Volo.Abp.Json { - public class AbpHasExtraPropertiesJsonConverter_Tests: AbpJsonTestBase + public class ExtensibleObject_Tests: AbpJsonTestBase { private readonly IJsonSerializer _jsonSerializer; - public AbpHasExtraPropertiesJsonConverter_Tests() + public ExtensibleObject_Tests() { _jsonSerializer = GetRequiredService(); } @@ -60,17 +60,54 @@ namespace Volo.Abp.Json fooDto.BarDtos.First().Name.ShouldBe("new-bar-dto"); fooDto.BarDtos.First().GetProperty("bar").ShouldBe("new-bar-value"); } + + [Fact] + public void SelfReference_Test() + { + var parentNodeDto = new NodeDto + { + Name = "parentNode", + }; + parentNodeDto.SetProperty("node", "parent-value"); + + var nodeDto = new NodeDto + { + Name = "node", + Parent = parentNodeDto + }; + nodeDto.SetProperty("node", "node-value"); + + var json = _jsonSerializer.Serialize(nodeDto); + + nodeDto = _jsonSerializer.Deserialize(json); + nodeDto.ShouldNotBeNull(); + nodeDto.Name.ShouldBe("node"); + nodeDto.GetProperty("node").ShouldBe("node-value"); + + nodeDto.Parent.ShouldNotBeNull(); + nodeDto.Parent.Name.ShouldBe("parentNode"); + nodeDto.Parent.GetProperty("node").ShouldBe("parent-value"); + } } - public class FooDto : ExtensibleObject + class FooDto : ExtensibleObject { public string Name { get; set; } public List BarDtos { get; set; } } - public class BarDto : ExtensibleObject + class BarDto : ExtensibleObject + { + public string Name { get; set; } + + public FooDto FooDto { get; set; } + } + + class NodeDto : ExtensibleObject { public string Name { get; set; } + + public NodeDto Parent { get; set; } } }