Skip to content

Commit 0ab246d

Browse files
authored
Flow IContractResolver through JsonPatch method calls (#40966)
1 parent 64ccf82 commit 0ab246d

File tree

8 files changed

+151
-13
lines changed

8 files changed

+151
-13
lines changed

src/Features/JsonPatch/src/Internal/DictionaryAdapterOfTU.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public virtual bool TryAdd(
3131
return false;
3232
}
3333

34-
if (!TryConvertValue(value, out var convertedValue, out errorMessage))
34+
if (!TryConvertValue(value, contractResolver, out var convertedValue, out errorMessage))
3535
{
3636
return false;
3737
}
@@ -119,7 +119,7 @@ public virtual bool TryReplace(
119119
return false;
120120
}
121121

122-
if (!TryConvertValue(value, out var convertedValue, out errorMessage))
122+
if (!TryConvertValue(value, contractResolver, out var convertedValue, out errorMessage))
123123
{
124124
return false;
125125
}
@@ -153,7 +153,7 @@ public virtual bool TryTest(
153153
return false;
154154
}
155155

156-
if (!TryConvertValue(value, out var convertedValue, out errorMessage))
156+
if (!TryConvertValue(value, contractResolver, out var convertedValue, out errorMessage))
157157
{
158158
return false;
159159
}
@@ -229,7 +229,12 @@ protected virtual bool TryConvertKey(string key, out TKey convertedKey, out stri
229229

230230
protected virtual bool TryConvertValue(object value, out TValue convertedValue, out string errorMessage)
231231
{
232-
var conversionResult = ConversionResultProvider.ConvertTo(value, typeof(TValue));
232+
return TryConvertValue(value, null, out convertedValue, out errorMessage);
233+
}
234+
235+
protected virtual bool TryConvertValue(object value, IContractResolver contractResolver, out TValue convertedValue, out string errorMessage)
236+
{
237+
var conversionResult = ConversionResultProvider.ConvertTo(value, typeof(TValue), contractResolver);
233238
if (conversionResult.CanBeConverted)
234239
{
235240
errorMessage = null;

src/Features/JsonPatch/src/Internal/DynamicObjectAdapter.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ public virtual bool TryReplace(
9292
return false;
9393
}
9494

95-
if (!TryConvertValue(value, property.GetType(), out var convertedValue))
95+
if (!TryConvertValue(value, property.GetType(), contractResolver, out var convertedValue))
9696
{
9797
errorMessage = Resources.FormatInvalidValueForProperty(value);
9898
return false;
@@ -124,7 +124,7 @@ public virtual bool TryTest(
124124
return false;
125125
}
126126

127-
if (!TryConvertValue(value, property.GetType(), out var convertedValue))
127+
if (!TryConvertValue(value, property.GetType(), contractResolver, out var convertedValue))
128128
{
129129
errorMessage = Resources.FormatInvalidValueForProperty(value);
130130
return false;
@@ -236,7 +236,12 @@ protected virtual bool TrySetDynamicObjectProperty(
236236

237237
protected virtual bool TryConvertValue(object value, Type propertyType, out object convertedValue)
238238
{
239-
var conversionResult = ConversionResultProvider.ConvertTo(value, propertyType);
239+
return TryConvertValue(value, propertyType, null, out convertedValue);
240+
}
241+
242+
protected virtual bool TryConvertValue(object value, Type propertyType, IContractResolver contractResolver, out object convertedValue)
243+
{
244+
var conversionResult = ConversionResultProvider.ConvertTo(value, propertyType, contractResolver);
240245
if (!conversionResult.CanBeConverted)
241246
{
242247
convertedValue = null;

src/Features/JsonPatch/src/Internal/PocoAdapter.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public virtual bool TryAdd(
3434
return false;
3535
}
3636

37-
if (!TryConvertValue(value, jsonProperty.PropertyType, out var convertedValue))
37+
if (!TryConvertValue(value, jsonProperty.PropertyType, contractResolver, out var convertedValue))
3838
{
3939
errorMessage = Resources.FormatInvalidValueForProperty(value);
4040
return false;
@@ -125,7 +125,7 @@ public virtual bool TryReplace(
125125
return false;
126126
}
127127

128-
if (!TryConvertValue(value, jsonProperty.PropertyType, out var convertedValue))
128+
if (!TryConvertValue(value, jsonProperty.PropertyType, contractResolver, out var convertedValue))
129129
{
130130
errorMessage = Resources.FormatInvalidValueForProperty(value);
131131
return false;
@@ -157,7 +157,7 @@ public virtual bool TryTest(
157157
return false;
158158
}
159159

160-
if (!TryConvertValue(value, jsonProperty.PropertyType, out var convertedValue))
160+
if (!TryConvertValue(value, jsonProperty.PropertyType, contractResolver, out var convertedValue))
161161
{
162162
errorMessage = Resources.FormatInvalidValueForProperty(value);
163163
return false;
@@ -225,7 +225,12 @@ protected virtual bool TryGetJsonProperty(
225225

226226
protected virtual bool TryConvertValue(object value, Type propertyType, out object convertedValue)
227227
{
228-
var conversionResult = ConversionResultProvider.ConvertTo(value, propertyType);
228+
return TryConvertValue(value, propertyType, null, out convertedValue);
229+
}
230+
231+
protected virtual bool TryConvertValue(object value, Type propertyType, IContractResolver contractResolver, out object convertedValue)
232+
{
233+
var conversionResult = ConversionResultProvider.ConvertTo(value, propertyType, contractResolver);
229234
if (!conversionResult.CanBeConverted)
230235
{
231236
convertedValue = null;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
#nullable enable
2+
~virtual Microsoft.AspNetCore.JsonPatch.Internal.DictionaryAdapter<TKey, TValue>.TryConvertValue(object value, Newtonsoft.Json.Serialization.IContractResolver contractResolver, out TValue convertedValue, out string errorMessage) -> bool
3+
~virtual Microsoft.AspNetCore.JsonPatch.Internal.DynamicObjectAdapter.TryConvertValue(object value, System.Type propertyType, Newtonsoft.Json.Serialization.IContractResolver contractResolver, out object convertedValue) -> bool
4+
~virtual Microsoft.AspNetCore.JsonPatch.Internal.PocoAdapter.TryConvertValue(object value, System.Type propertyType, Newtonsoft.Json.Serialization.IContractResolver contractResolver, out object convertedValue) -> bool

src/Features/JsonPatch/test/Internal/DictionaryAdapterTest.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
using System;
55
using System.Collections.Generic;
66
using System.Globalization;
7+
using System.Linq;
8+
using Newtonsoft.Json;
9+
using Newtonsoft.Json.Converters;
710
using Newtonsoft.Json.Serialization;
811
using Xunit;
912

@@ -228,6 +231,29 @@ public void Remove_NonExistingKey_Fails()
228231
Assert.Empty(dictionary);
229232
}
230233

234+
[Fact]
235+
public void Replace_UsesCustomConverter()
236+
{
237+
// Arrange
238+
var nameKey = "Name";
239+
var dictionary = new Dictionary<string, Rectangle>(StringComparer.Ordinal);
240+
dictionary.Add(nameKey, new Rectangle()
241+
{
242+
RectangleProperty = "Mike"
243+
});
244+
var dictionaryAdapter = new DictionaryAdapter<string, Rectangle>();
245+
var resolver = new RectangleContractResolver();
246+
247+
// Act
248+
var replaceStatus = dictionaryAdapter.TryReplace(dictionary, nameKey, resolver, "James", out var message);
249+
250+
// Assert
251+
Assert.True(replaceStatus);
252+
Assert.True(string.IsNullOrEmpty(message), "Expected no error message");
253+
Assert.Single(dictionary);
254+
Assert.Equal("James", dictionary[nameKey].RectangleProperty);
255+
}
256+
231257
[Fact]
232258
public void Remove_RemovesFromDictionary()
233259
{

src/Features/JsonPatch/test/Internal/DynamicObjectAdapterTest.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Licensed to the .NET Foundation under one or more agreements.
1+
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Collections.Generic;
@@ -183,6 +183,27 @@ public void TryReplace_ThrowsPropertyInvalidException_IfNewValueIsNotTheSameType
183183
Assert.Equal($"The value 'test' is invalid for target location.", errorMessage);
184184
}
185185

186+
[Fact]
187+
public void TryReplace_UsesCustomConverter()
188+
{
189+
// Arrange
190+
var adapter = new DynamicObjectAdapter();
191+
dynamic target = new WriteOnceDynamicTestObject();
192+
target.NewProperty = new Rectangle();
193+
var segment = "NewProperty";
194+
var resolver = new RectangleContractResolver();
195+
196+
// Act
197+
var status = adapter.TryReplace(target, segment, resolver, "new", out string errorMessage);
198+
199+
// Assert
200+
Assert.True(status);
201+
Assert.Null(errorMessage);
202+
Assert.True(target.NewProperty is Rectangle);
203+
var rect = (Rectangle)target.NewProperty;
204+
Assert.Equal("new", rect.RectangleProperty);
205+
}
206+
186207
[Theory]
187208
[InlineData(1, 0)]
188209
[InlineData("new", null)]

src/Features/JsonPatch/test/Internal/PocoAdapterTest.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
// Licensed to the .NET Foundation under one or more agreements.
1+
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using Microsoft.AspNetCore.JsonPatch.IntegrationTests;
8+
using Newtonsoft.Json;
9+
using Newtonsoft.Json.Converters;
10+
using Newtonsoft.Json.Linq;
411
using Newtonsoft.Json.Serialization;
512
using Xunit;
613

@@ -192,6 +199,28 @@ public void TryReplace_ThrowsJsonPatchException_IfPropertyDoesNotExist()
192199
Assert.Equal(expectedErrorMessage, errorMessage);
193200
}
194201

202+
[Fact]
203+
public void TryReplace_UsesCustomConverter()
204+
{
205+
// Arrange
206+
var adapter = new PocoAdapter();
207+
var contractResolver = new RectangleContractResolver();
208+
var model = new Square()
209+
{
210+
Rectangle = new Rectangle()
211+
{
212+
RectangleProperty = "Square"
213+
}
214+
};
215+
216+
// Act
217+
var replaceStatus = adapter.TryReplace(model, "Rectangle", contractResolver, "Oval", out var errorMessage);
218+
219+
// Assert
220+
Assert.Equal("Oval", model.Rectangle.RectangleProperty);
221+
Assert.True(replaceStatus);
222+
}
223+
195224
[Fact]
196225
public void TryTest_DoesNotThrowException_IfTestSuccessful()
197226
{

src/Features/JsonPatch/test/TestObjectModels/HeterogenousCollection.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System;
45
using System.Collections.Generic;
6+
using Newtonsoft.Json;
7+
using Newtonsoft.Json.Converters;
8+
using Newtonsoft.Json.Serialization;
59

610
namespace Microsoft.AspNetCore.JsonPatch;
711

@@ -20,7 +24,47 @@ public class Rectangle : Shape
2024
public string RectangleProperty { get; set; }
2125
}
2226

27+
public class Square : Shape
28+
{
29+
public Rectangle Rectangle { get; set; }
30+
}
31+
2332
public class Canvas
2433
{
2534
public IList<Shape> Items { get; set; }
2635
}
36+
37+
public class RectangleContractResolver : DefaultContractResolver
38+
{
39+
protected override JsonConverter ResolveContractConverter(Type objectType)
40+
{
41+
if (objectType == typeof(Rectangle))
42+
{
43+
return new RectangleJsonConverter();
44+
}
45+
46+
return base.ResolveContractConverter(objectType);
47+
}
48+
}
49+
50+
public class RectangleJsonConverter : CustomCreationConverter<Rectangle>
51+
{
52+
public override bool CanRead => true;
53+
54+
public override Rectangle Create(Type objectType)
55+
{
56+
throw new NotImplementedException();
57+
}
58+
59+
public override object ReadJson(
60+
JsonReader reader,
61+
Type objectType,
62+
object existingValue,
63+
JsonSerializer serializer)
64+
{
65+
return new Rectangle()
66+
{
67+
RectangleProperty = reader.Value.ToString()
68+
};
69+
}
70+
}

0 commit comments

Comments
 (0)