Browse Source

Merge pull request #6163 from abpframework/maliming/AbpExtraPropertyDictionaryJsonConverter

Add AbpExtraPropertyDictionaryJsonConverter.
pull/6166/head
liangshiwei 6 years ago
committed by GitHub
parent
commit
11e801ddf9
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs
  2. 21
      framework/src/Volo.Abp.Core/System/Text/Json/JsonSerializerOptionsHelper.cs
  3. 1
      framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj
  4. 5
      framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs
  5. 42
      framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpExtraPropertyDictionaryJsonConverter.cs
  6. 26
      framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpExtraPropertyDictionaryJsonConverterFactory.cs
  7. 5
      framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToBooleanConverter.cs
  8. 12
      framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumConverter.cs
  9. 3
      framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/ObjectToInferredTypesConverter.cs
  10. 20
      framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs
  11. 3
      framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/JsonConverters/EntityJsonConverter.cs
  12. 17
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/JsonSerializerOptionsHelper.cs
  13. 4
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemSourceJsonConverter.cs
  14. 2
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/StringValueTypeJsonConverter.cs
  15. 6
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/ValueValidatorJsonConverter.cs

3
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs

@ -27,6 +27,9 @@ namespace Volo.Abp.AspNetCore.Mvc.Json
options.JsonSerializerOptions.Converters.Add(new AbpStringToEnumFactory());
options.JsonSerializerOptions.Converters.Add(new AbpStringToBooleanConverter());
options.JsonSerializerOptions.Converters.Add(new ObjectToInferredTypesConverter());
options.JsonSerializerOptions.Converters.Add(new AbpExtraPropertyDictionaryJsonConverterFactory());
}
}
}

21
framework/src/Volo.Abp.Core/System/Text/Json/JsonSerializerOptionsHelper.cs

@ -0,0 +1,21 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace System.Text.Json
{
public static class JsonSerializerOptionsHelper
{
public static JsonSerializerOptions Create(JsonSerializerOptions baseOptions, JsonConverter removeConverter, params JsonConverter[] addConverters)
{
return Create(baseOptions, x => x == removeConverter, addConverters);
}
public static JsonSerializerOptions Create(JsonSerializerOptions baseOptions, Func<JsonConverter, bool> removeConverterPredicate, params JsonConverter[] addConverters)
{
var options = new JsonSerializerOptions(baseOptions);
options.Converters.RemoveAll(removeConverterPredicate);
options.Converters.AddIfNotContains(addConverters);
return options;
}
}
}

1
framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj

@ -16,6 +16,7 @@
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Timing\Volo.Abp.Timing.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.ObjectExtending\Volo.Abp.ObjectExtending.csproj" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>

5
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs

@ -1,4 +1,4 @@
using System;
using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.Json.SystemTextJson.JsonConverters;
@ -21,6 +21,9 @@ namespace Volo.Abp.Json.SystemTextJson
options.JsonSerializerOptions.Converters.Add(new AbpStringToEnumFactory());
options.JsonSerializerOptions.Converters.Add(new AbpStringToBooleanConverter());
options.JsonSerializerOptions.Converters.Add(new ObjectToInferredTypesConverter());
options.JsonSerializerOptions.Converters.Add(new AbpExtraPropertyDictionaryJsonConverterFactory());
}
}
}

42
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpExtraPropertyDictionaryJsonConverter.cs

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using Volo.Abp.Data;
using Volo.Abp.ObjectExtending;
namespace Volo.Abp.Json.SystemTextJson.JsonConverters
{
public class AbpExtraPropertyDictionaryJsonConverter<T> : JsonConverter<T>
where T : ExtensibleObject
{
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var newOptions = JsonSerializerOptionsHelper.Create(options, x =>
x == this ||
x.GetType() == typeof(AbpExtraPropertyDictionaryJsonConverterFactory));
var rootElement = JsonDocument.ParseValue(ref reader).RootElement;
var extensibleObject = JsonSerializer.Deserialize<T>(rootElement.GetRawText(), newOptions);
var extraProperties = rootElement.EnumerateObject().FirstOrDefault(x =>
x.Name.Equals(nameof(ExtensibleObject.ExtraProperties), StringComparison.OrdinalIgnoreCase))
.Value.GetRawText();
var extraPropertyDictionary = JsonSerializer.Deserialize(extraProperties, typeof(ExtraPropertyDictionary), newOptions);
ObjectHelper.TrySetProperty(extensibleObject, x => x.ExtraProperties, () => extraPropertyDictionary);
return extensibleObject;
}
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
{
var newOptions = JsonSerializerOptionsHelper.Create(options, x =>
x == this ||
x.GetType() == typeof(AbpExtraPropertyDictionaryJsonConverterFactory));
JsonSerializer.Serialize(writer, value, newOptions);
}
}
}

26
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpExtraPropertyDictionaryJsonConverterFactory.cs

@ -0,0 +1,26 @@
using System;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
using Volo.Abp.ObjectExtending;
namespace Volo.Abp.Json.SystemTextJson.JsonConverters
{
public class AbpExtraPropertyDictionaryJsonConverterFactory : JsonConverterFactory
{
public override bool CanConvert(Type typeToConvert)
{
return typeToConvert == typeof(ExtensibleObject) || typeToConvert.IsSubclassOf(typeof(ExtensibleObject));
}
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
return (JsonConverter) Activator.CreateInstance(
typeof(AbpExtraPropertyDictionaryJsonConverter<>).MakeGenericType(typeToConvert),
BindingFlags.Instance | BindingFlags.Public,
binder: null,
null,
culture: null)!;
}
}
}

5
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToBooleanConverter.cs

@ -1,4 +1,4 @@
using System;
using System;
using System.Buffers;
using System.Buffers.Text;
using System.Text.Json;
@ -29,8 +29,7 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters
public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options)
{
var newOptions = new JsonSerializerOptions(options);
newOptions.Converters.Remove(this);
var newOptions = JsonSerializerOptionsHelper.Create(options, this);
var entityConverter = (JsonConverter<bool>)newOptions.GetConverter(typeof(bool));
entityConverter.Write(writer, value, newOptions);
}

12
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumConverter.cs

@ -28,16 +28,20 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var newOptions = new JsonSerializerOptions(options);
newOptions.Converters.RemoveAll(x => x == this || x.GetType() == typeof(AbpStringToEnumFactory));
var newOptions = JsonSerializerOptionsHelper.Create(options, x =>
x == this ||
x.GetType() == typeof(AbpStringToEnumFactory));
newOptions.Converters.Add(_innerJsonStringEnumConverter.CreateConverter(typeToConvert, newOptions));
return JsonSerializer.Deserialize<T>(ref reader, newOptions);
}
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
{
var newOptions = new JsonSerializerOptions(options);
newOptions.Converters.RemoveAll(x => x == this || x.GetType() == typeof(AbpStringToEnumFactory));
var newOptions = JsonSerializerOptionsHelper.Create(options, x =>
x == this ||
x.GetType() == typeof(AbpStringToEnumFactory));
JsonSerializer.Serialize(writer, value, newOptions);
}
}

3
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/ObjectToInferredTypesConverter.cs

@ -51,7 +51,8 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters
public override void Write(Utf8JsonWriter writer, object objectToWrite, JsonSerializerOptions options)
{
throw new InvalidOperationException("Should not get here.");
var newOptions = JsonSerializerOptionsHelper.Create(options, this);
JsonSerializer.Serialize(writer, objectToWrite, newOptions);
}
}
}

20
framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs

@ -1,5 +1,7 @@
using Shouldly;
using Volo.Abp.Data;
using Volo.Abp.Json.SystemTextJson;
using Volo.Abp.ObjectExtending;
using Xunit;
namespace Volo.Abp.Json
@ -78,6 +80,24 @@ namespace Volo.Abp.Json
newJson.ShouldBe("{\"name\":\"abp\",\"type\":2}");
}
[Fact]
public void Serialize_Deserialize_ExtensibleObject()
{
var json = "{\"name\":\"test\",\"extraProperties\":{\"One\":\"123\",\"Two\":456}}";
var extensibleObject = _jsonSerializer.Deserialize<TestExtensibleObjectClass>(json);
extensibleObject.GetProperty("One").ShouldBe("123");
extensibleObject.GetProperty("Two").ShouldBe(456);
var newJson = _jsonSerializer.Serialize(extensibleObject);
newJson.ShouldBe(json);
}
class TestExtensibleObjectClass : ExtensibleObject
{
public string Name { get; set; }
}
class FileWithBoolean
{
public string Name { get; set; }

3
framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/JsonConverters/EntityJsonConverter.cs

@ -25,8 +25,7 @@ namespace Volo.Abp.MemoryDb.JsonConverters
public override void Write(Utf8JsonWriter writer, TEntity value, JsonSerializerOptions options)
{
var newOptions = new JsonSerializerOptions(options);
newOptions.Converters.Remove(this);
var newOptions = JsonSerializerOptionsHelper.Create(options, this);
var entityConverter = (JsonConverter<TEntity>)newOptions.GetConverter(typeof(TEntity));
entityConverter.Write(writer, value, newOptions);
}

17
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/JsonSerializerOptionsHelper.cs

@ -1,17 +0,0 @@
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Volo.Abp.FeatureManagement.JsonConverters
{
internal static class JsonSerializerOptionsHelper
{
public static JsonSerializerOptions Create(JsonSerializerOptions baseOptions, JsonConverter removeConverter, params JsonConverter[] addConverters)
{
var options = new JsonSerializerOptions(baseOptions);
options.Converters.RemoveAll(x => x == removeConverter);
options.Converters.AddIfNotContains(addConverters);
return options;
}
}
}

4
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemSourceJsonConverter.cs

@ -14,13 +14,13 @@ namespace Volo.Abp.FeatureManagement.JsonConverters
var newOptions = JsonSerializerOptionsHelper.Create(options, this);
var rootElement = JsonDocument.ParseValue(ref reader).RootElement;
var items = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals("Items", StringComparison.InvariantCultureIgnoreCase)).Value.GetRawText();
var items = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(ISelectionStringValueItemSource.Items), StringComparison.OrdinalIgnoreCase)).Value.GetRawText();
var selectionStringValueItem =
JsonSerializer.Deserialize<List<LocalizableSelectionStringValueItem>>(items, newOptions) ??
new List<LocalizableSelectionStringValueItem>();
return new StaticSelectionStringValueItemSource(selectionStringValueItem.ToArray());
return new StaticSelectionStringValueItemSource(selectionStringValueItem.ToArray().As<ISelectionStringValueItem[]>());
}
public override void Write(Utf8JsonWriter writer, ISelectionStringValueItemSource value, JsonSerializerOptions options)

2
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/StringValueTypeJsonConverter.cs

@ -11,7 +11,7 @@ namespace Volo.Abp.FeatureManagement.JsonConverters
public override IStringValueType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var rootElement = JsonDocument.ParseValue(ref reader).RootElement;
var name = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals("Name", StringComparison.InvariantCultureIgnoreCase)).Value.GetString();
var name = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IStringValueType.Name), StringComparison.OrdinalIgnoreCase)).Value.GetString();
var newOptions = JsonSerializerOptionsHelper.Create(options, this, new ValueValidatorJsonConverter(), new SelectionStringValueItemSourceJsonConverter());
return name switch
{

6
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/ValueValidatorJsonConverter.cs

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
@ -13,10 +13,10 @@ namespace Volo.Abp.FeatureManagement.JsonConverters
public override IValueValidator Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var rootElement = JsonDocument.ParseValue(ref reader).RootElement;
var name = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals("Name", StringComparison.InvariantCultureIgnoreCase)).Value.GetString();
var name = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IValueValidator.Name), StringComparison.OrdinalIgnoreCase)).Value.GetString();
var valueValidator = CreateValueValidatorByName(name);
var propertiesRawText = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals("Properties", StringComparison.InvariantCultureIgnoreCase)).Value.GetRawText();
var propertiesRawText = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IValueValidator.Properties), StringComparison.OrdinalIgnoreCase)).Value.GetRawText();
var newOptions = JsonSerializerOptionsHelper.Create(options, this, new ObjectToInferredTypesConverter());
var properties = JsonSerializer.Deserialize<IDictionary<string, object>>(propertiesRawText, newOptions);
if (properties != null && properties.Any())

Loading…
Cancel
Save