diff options
author | mboggs1 <102692996+mboggs1@users.noreply.github.com> | 2022-04-19 03:32:17 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-19 03:32:17 +0300 |
commit | 0ab246d2ee8add862262f24e990154284a8a4631 (patch) | |
tree | ee55d4da23fa441adf936f95209ee77989c5f445 | |
parent | 64ccf823287a1de02385d29497127ad5197a389d (diff) |
Flow IContractResolver through JsonPatch method calls (#40966)
8 files changed, 151 insertions, 13 deletions
diff --git a/src/Features/JsonPatch/src/Internal/DictionaryAdapterOfTU.cs b/src/Features/JsonPatch/src/Internal/DictionaryAdapterOfTU.cs index 0b7cad675a..6dc39a5376 100644 --- a/src/Features/JsonPatch/src/Internal/DictionaryAdapterOfTU.cs +++ b/src/Features/JsonPatch/src/Internal/DictionaryAdapterOfTU.cs @@ -31,7 +31,7 @@ public class DictionaryAdapter<TKey, TValue> : IAdapter return false; } - if (!TryConvertValue(value, out var convertedValue, out errorMessage)) + if (!TryConvertValue(value, contractResolver, out var convertedValue, out errorMessage)) { return false; } @@ -119,7 +119,7 @@ public class DictionaryAdapter<TKey, TValue> : IAdapter return false; } - if (!TryConvertValue(value, out var convertedValue, out errorMessage)) + if (!TryConvertValue(value, contractResolver, out var convertedValue, out errorMessage)) { return false; } @@ -153,7 +153,7 @@ public class DictionaryAdapter<TKey, TValue> : IAdapter return false; } - if (!TryConvertValue(value, out var convertedValue, out errorMessage)) + if (!TryConvertValue(value, contractResolver, out var convertedValue, out errorMessage)) { return false; } @@ -229,7 +229,12 @@ public class DictionaryAdapter<TKey, TValue> : IAdapter protected virtual bool TryConvertValue(object value, out TValue convertedValue, out string errorMessage) { - var conversionResult = ConversionResultProvider.ConvertTo(value, typeof(TValue)); + return TryConvertValue(value, null, out convertedValue, out errorMessage); + } + + protected virtual bool TryConvertValue(object value, IContractResolver contractResolver, out TValue convertedValue, out string errorMessage) + { + var conversionResult = ConversionResultProvider.ConvertTo(value, typeof(TValue), contractResolver); if (conversionResult.CanBeConverted) { errorMessage = null; diff --git a/src/Features/JsonPatch/src/Internal/DynamicObjectAdapter.cs b/src/Features/JsonPatch/src/Internal/DynamicObjectAdapter.cs index 626030e260..64168364d9 100644 --- a/src/Features/JsonPatch/src/Internal/DynamicObjectAdapter.cs +++ b/src/Features/JsonPatch/src/Internal/DynamicObjectAdapter.cs @@ -92,7 +92,7 @@ public class DynamicObjectAdapter : IAdapter return false; } - if (!TryConvertValue(value, property.GetType(), out var convertedValue)) + if (!TryConvertValue(value, property.GetType(), contractResolver, out var convertedValue)) { errorMessage = Resources.FormatInvalidValueForProperty(value); return false; @@ -124,7 +124,7 @@ public class DynamicObjectAdapter : IAdapter return false; } - if (!TryConvertValue(value, property.GetType(), out var convertedValue)) + if (!TryConvertValue(value, property.GetType(), contractResolver, out var convertedValue)) { errorMessage = Resources.FormatInvalidValueForProperty(value); return false; @@ -236,7 +236,12 @@ public class DynamicObjectAdapter : IAdapter protected virtual bool TryConvertValue(object value, Type propertyType, out object convertedValue) { - var conversionResult = ConversionResultProvider.ConvertTo(value, propertyType); + return TryConvertValue(value, propertyType, null, out convertedValue); + } + + protected virtual bool TryConvertValue(object value, Type propertyType, IContractResolver contractResolver, out object convertedValue) + { + var conversionResult = ConversionResultProvider.ConvertTo(value, propertyType, contractResolver); if (!conversionResult.CanBeConverted) { convertedValue = null; diff --git a/src/Features/JsonPatch/src/Internal/PocoAdapter.cs b/src/Features/JsonPatch/src/Internal/PocoAdapter.cs index 49f8fe1869..00d613e3ae 100644 --- a/src/Features/JsonPatch/src/Internal/PocoAdapter.cs +++ b/src/Features/JsonPatch/src/Internal/PocoAdapter.cs @@ -34,7 +34,7 @@ public class PocoAdapter : IAdapter return false; } - if (!TryConvertValue(value, jsonProperty.PropertyType, out var convertedValue)) + if (!TryConvertValue(value, jsonProperty.PropertyType, contractResolver, out var convertedValue)) { errorMessage = Resources.FormatInvalidValueForProperty(value); return false; @@ -125,7 +125,7 @@ public class PocoAdapter : IAdapter return false; } - if (!TryConvertValue(value, jsonProperty.PropertyType, out var convertedValue)) + if (!TryConvertValue(value, jsonProperty.PropertyType, contractResolver, out var convertedValue)) { errorMessage = Resources.FormatInvalidValueForProperty(value); return false; @@ -157,7 +157,7 @@ public class PocoAdapter : IAdapter return false; } - if (!TryConvertValue(value, jsonProperty.PropertyType, out var convertedValue)) + if (!TryConvertValue(value, jsonProperty.PropertyType, contractResolver, out var convertedValue)) { errorMessage = Resources.FormatInvalidValueForProperty(value); return false; @@ -225,7 +225,12 @@ public class PocoAdapter : IAdapter protected virtual bool TryConvertValue(object value, Type propertyType, out object convertedValue) { - var conversionResult = ConversionResultProvider.ConvertTo(value, propertyType); + return TryConvertValue(value, propertyType, null, out convertedValue); + } + + protected virtual bool TryConvertValue(object value, Type propertyType, IContractResolver contractResolver, out object convertedValue) + { + var conversionResult = ConversionResultProvider.ConvertTo(value, propertyType, contractResolver); if (!conversionResult.CanBeConverted) { convertedValue = null; diff --git a/src/Features/JsonPatch/src/PublicAPI.Unshipped.txt b/src/Features/JsonPatch/src/PublicAPI.Unshipped.txt index 7dc5c58110..26ee55ba6f 100644 --- a/src/Features/JsonPatch/src/PublicAPI.Unshipped.txt +++ b/src/Features/JsonPatch/src/PublicAPI.Unshipped.txt @@ -1 +1,4 @@ #nullable enable +~virtual Microsoft.AspNetCore.JsonPatch.Internal.DictionaryAdapter<TKey, TValue>.TryConvertValue(object value, Newtonsoft.Json.Serialization.IContractResolver contractResolver, out TValue convertedValue, out string errorMessage) -> bool +~virtual Microsoft.AspNetCore.JsonPatch.Internal.DynamicObjectAdapter.TryConvertValue(object value, System.Type propertyType, Newtonsoft.Json.Serialization.IContractResolver contractResolver, out object convertedValue) -> bool +~virtual Microsoft.AspNetCore.JsonPatch.Internal.PocoAdapter.TryConvertValue(object value, System.Type propertyType, Newtonsoft.Json.Serialization.IContractResolver contractResolver, out object convertedValue) -> bool diff --git a/src/Features/JsonPatch/test/Internal/DictionaryAdapterTest.cs b/src/Features/JsonPatch/test/Internal/DictionaryAdapterTest.cs index 5f6ee3ee9c..6d6d491952 100644 --- a/src/Features/JsonPatch/test/Internal/DictionaryAdapterTest.cs +++ b/src/Features/JsonPatch/test/Internal/DictionaryAdapterTest.cs @@ -4,6 +4,9 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; using Newtonsoft.Json.Serialization; using Xunit; @@ -229,6 +232,29 @@ public class DictionaryAdapterTest } [Fact] + public void Replace_UsesCustomConverter() + { + // Arrange + var nameKey = "Name"; + var dictionary = new Dictionary<string, Rectangle>(StringComparer.Ordinal); + dictionary.Add(nameKey, new Rectangle() + { + RectangleProperty = "Mike" + }); + var dictionaryAdapter = new DictionaryAdapter<string, Rectangle>(); + var resolver = new RectangleContractResolver(); + + // Act + var replaceStatus = dictionaryAdapter.TryReplace(dictionary, nameKey, resolver, "James", out var message); + + // Assert + Assert.True(replaceStatus); + Assert.True(string.IsNullOrEmpty(message), "Expected no error message"); + Assert.Single(dictionary); + Assert.Equal("James", dictionary[nameKey].RectangleProperty); + } + + [Fact] public void Remove_RemovesFromDictionary() { // Arrange diff --git a/src/Features/JsonPatch/test/Internal/DynamicObjectAdapterTest.cs b/src/Features/JsonPatch/test/Internal/DynamicObjectAdapterTest.cs index 021dd13100..fc3d5c0825 100644 --- a/src/Features/JsonPatch/test/Internal/DynamicObjectAdapterTest.cs +++ b/src/Features/JsonPatch/test/Internal/DynamicObjectAdapterTest.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; @@ -183,6 +183,27 @@ public class DynamicObjectAdapterTest Assert.Equal($"The value 'test' is invalid for target location.", errorMessage); } + [Fact] + public void TryReplace_UsesCustomConverter() + { + // Arrange + var adapter = new DynamicObjectAdapter(); + dynamic target = new WriteOnceDynamicTestObject(); + target.NewProperty = new Rectangle(); + var segment = "NewProperty"; + var resolver = new RectangleContractResolver(); + + // Act + var status = adapter.TryReplace(target, segment, resolver, "new", out string errorMessage); + + // Assert + Assert.True(status); + Assert.Null(errorMessage); + Assert.True(target.NewProperty is Rectangle); + var rect = (Rectangle)target.NewProperty; + Assert.Equal("new", rect.RectangleProperty); + } + [Theory] [InlineData(1, 0)] [InlineData("new", null)] diff --git a/src/Features/JsonPatch/test/Internal/PocoAdapterTest.cs b/src/Features/JsonPatch/test/Internal/PocoAdapterTest.cs index 47584c6953..891a3b1e30 100644 --- a/src/Features/JsonPatch/test/Internal/PocoAdapterTest.cs +++ b/src/Features/JsonPatch/test/Internal/PocoAdapterTest.cs @@ -1,6 +1,13 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.JsonPatch.IntegrationTests; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; using Xunit; @@ -193,6 +200,28 @@ public class PocoAdapterTest } [Fact] + public void TryReplace_UsesCustomConverter() + { + // Arrange + var adapter = new PocoAdapter(); + var contractResolver = new RectangleContractResolver(); + var model = new Square() + { + Rectangle = new Rectangle() + { + RectangleProperty = "Square" + } + }; + + // Act + var replaceStatus = adapter.TryReplace(model, "Rectangle", contractResolver, "Oval", out var errorMessage); + + // Assert + Assert.Equal("Oval", model.Rectangle.RectangleProperty); + Assert.True(replaceStatus); + } + + [Fact] public void TryTest_DoesNotThrowException_IfTestSuccessful() { var adapter = new PocoAdapter(); diff --git a/src/Features/JsonPatch/test/TestObjectModels/HeterogenousCollection.cs b/src/Features/JsonPatch/test/TestObjectModels/HeterogenousCollection.cs index e9d5f4e466..d1520dd7d0 100644 --- a/src/Features/JsonPatch/test/TestObjectModels/HeterogenousCollection.cs +++ b/src/Features/JsonPatch/test/TestObjectModels/HeterogenousCollection.cs @@ -1,7 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; namespace Microsoft.AspNetCore.JsonPatch; @@ -20,7 +24,47 @@ public class Rectangle : Shape public string RectangleProperty { get; set; } } +public class Square : Shape +{ + public Rectangle Rectangle { get; set; } +} + public class Canvas { public IList<Shape> Items { get; set; } } + +public class RectangleContractResolver : DefaultContractResolver +{ + protected override JsonConverter ResolveContractConverter(Type objectType) + { + if (objectType == typeof(Rectangle)) + { + return new RectangleJsonConverter(); + } + + return base.ResolveContractConverter(objectType); + } +} + +public class RectangleJsonConverter : CustomCreationConverter<Rectangle> +{ + public override bool CanRead => true; + + public override Rectangle Create(Type objectType) + { + throw new NotImplementedException(); + } + + public override object ReadJson( + JsonReader reader, + Type objectType, + object existingValue, + JsonSerializer serializer) + { + return new Rectangle() + { + RectangleProperty = reader.Value.ToString() + }; + } +} |