* Fix for issue #29 (Honor JsonProperty when serializing a JsonPatchDocument)
This commit is contained in:
parent
e72d4b4876
commit
c88aa0042a
|
|
@ -1,9 +1,12 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.JsonPatch.Helpers
|
namespace Microsoft.AspNetCore.JsonPatch.Helpers
|
||||||
{
|
{
|
||||||
|
|
@ -51,11 +54,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Helpers
|
||||||
if (ContinueWithSubPath(memberExpression.Expression.NodeType, false))
|
if (ContinueWithSubPath(memberExpression.Expression.NodeType, false))
|
||||||
{
|
{
|
||||||
var left = GetPath(memberExpression.Expression, false);
|
var left = GetPath(memberExpression.Expression, false);
|
||||||
return left + "/" + memberExpression.Member.Name;
|
// Get property name, respecting JsonProperty attribute
|
||||||
|
return left + "/" + GetPropertyNameFromMemberExpression(memberExpression);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return memberExpression.Member.Name;
|
// Get property name, respecting JsonProperty attribute
|
||||||
|
return GetPropertyNameFromMemberExpression(memberExpression);
|
||||||
}
|
}
|
||||||
case ExpressionType.Parameter:
|
case ExpressionType.Parameter:
|
||||||
// Fits "x => x" (the whole document which is "" as JSON pointer)
|
// Fits "x => x" (the whole document which is "" as JSON pointer)
|
||||||
|
|
@ -65,6 +70,23 @@ namespace Microsoft.AspNetCore.JsonPatch.Helpers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GetPropertyNameFromMemberExpression(MemberExpression memberExpression)
|
||||||
|
{
|
||||||
|
// if there's a JsonProperty attribute, we must return the PropertyName
|
||||||
|
// from the attribute rather than the member name
|
||||||
|
var jsonPropertyAttribute =
|
||||||
|
memberExpression.Member.GetCustomAttribute(
|
||||||
|
typeof(JsonPropertyAttribute), true);
|
||||||
|
|
||||||
|
if (jsonPropertyAttribute == null)
|
||||||
|
{
|
||||||
|
return memberExpression.Member.Name;
|
||||||
|
}
|
||||||
|
// get value
|
||||||
|
var castedAttribute = (JsonPropertyAttribute)jsonPropertyAttribute;
|
||||||
|
return castedAttribute.PropertyName;
|
||||||
|
}
|
||||||
|
|
||||||
private static bool ContinueWithSubPath(ExpressionType expressionType, bool firstTime)
|
private static bool ContinueWithSubPath(ExpressionType expressionType, bool firstTime)
|
||||||
{
|
{
|
||||||
if (firstTime)
|
if (firstTime)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,148 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Linq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.JsonPatch
|
||||||
|
{
|
||||||
|
public class JsonPatchDocumentJsonPropertyAttributeTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Add_WithExpression_RespectsJsonPropertyName_ForModelProperty()
|
||||||
|
{
|
||||||
|
var patchDoc = new JsonPatchDocument<JsonPropertyDTO>();
|
||||||
|
patchDoc.Add(p => p.Name, "John");
|
||||||
|
|
||||||
|
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||||
|
// serialized value should have "AnotherName" as path
|
||||||
|
// deserialize to a JsonPatchDocument<JsonPropertyWithAnotherNameDTO> to check
|
||||||
|
var deserialized =
|
||||||
|
JsonConvert.DeserializeObject<JsonPatchDocument<JsonPropertyWithAnotherNameDTO>>(serialized);
|
||||||
|
|
||||||
|
// get path
|
||||||
|
var pathToCheck = deserialized.Operations.First().path;
|
||||||
|
Assert.Equal(pathToCheck, "/anothername");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Add_WithExpression_RespectsJsonPropertyName_WhenApplyingToDifferentlyTypedClassWithPropertyMatchingJsonPropertyName()
|
||||||
|
{
|
||||||
|
var patchDocToSerialize = new JsonPatchDocument<JsonPropertyDTO>();
|
||||||
|
patchDocToSerialize.Add(p => p.Name, "John");
|
||||||
|
|
||||||
|
// the patchdoc will deserialize to "anothername". We should thus be able to apply
|
||||||
|
// it to a class that HAS that other property name.
|
||||||
|
var doc = new JsonPropertyWithAnotherNameDTO()
|
||||||
|
{
|
||||||
|
AnotherName = "InitialValue"
|
||||||
|
};
|
||||||
|
|
||||||
|
var serialized = JsonConvert.SerializeObject(patchDocToSerialize);
|
||||||
|
var deserialized =
|
||||||
|
JsonConvert.DeserializeObject<JsonPatchDocument<JsonPropertyWithAnotherNameDTO>>
|
||||||
|
(serialized);
|
||||||
|
|
||||||
|
deserialized.ApplyTo(doc);
|
||||||
|
|
||||||
|
Assert.Equal(doc.AnotherName, "John");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Add_WithExpression_RespectsJsonPropertyName_WhenApplyingToSameTypedClassWithMatchingJsonPropertyName()
|
||||||
|
{
|
||||||
|
var patchDocToSerialize = new JsonPatchDocument<JsonPropertyDTO>();
|
||||||
|
patchDocToSerialize.Add(p => p.Name, "John");
|
||||||
|
|
||||||
|
// the patchdoc will deserialize to "anothername". As JsonPropertyDTO has
|
||||||
|
// a JsonProperty signifying that "Name" should be deseriallized from "AnotherName",
|
||||||
|
// we should be able to apply the patchDoc.
|
||||||
|
|
||||||
|
var doc = new JsonPropertyDTO()
|
||||||
|
{
|
||||||
|
Name = "InitialValue"
|
||||||
|
};
|
||||||
|
|
||||||
|
var serialized = JsonConvert.SerializeObject(patchDocToSerialize);
|
||||||
|
var deserialized =
|
||||||
|
JsonConvert.DeserializeObject<JsonPatchDocument<JsonPropertyDTO>>
|
||||||
|
(serialized);
|
||||||
|
|
||||||
|
deserialized.ApplyTo(doc);
|
||||||
|
|
||||||
|
Assert.Equal(doc.Name, "John");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Add_OnApplyFromJson_RespectsJsonPropertyNameOnJsonDocument()
|
||||||
|
{
|
||||||
|
var doc = new JsonPropertyDTO()
|
||||||
|
{
|
||||||
|
Name = "InitialValue"
|
||||||
|
};
|
||||||
|
|
||||||
|
// serialization should serialize to "AnotherName"
|
||||||
|
var serialized = "[{\"value\":\"Kevin\",\"path\":\"/AnotherName\",\"op\":\"add\"}]";
|
||||||
|
var deserialized =
|
||||||
|
JsonConvert.DeserializeObject<JsonPatchDocument<JsonPropertyDTO>>(serialized);
|
||||||
|
|
||||||
|
deserialized.ApplyTo(doc);
|
||||||
|
|
||||||
|
Assert.Equal("Kevin", doc.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Remove_OnApplyFromJson_RespectsJsonPropertyNameOnJsonDocument()
|
||||||
|
{
|
||||||
|
var doc = new JsonPropertyDTO()
|
||||||
|
{
|
||||||
|
Name = "InitialValue"
|
||||||
|
};
|
||||||
|
|
||||||
|
// serialization should serialize to "AnotherName"
|
||||||
|
var serialized = "[{\"path\":\"/AnotherName\",\"op\":\"remove\"}]";
|
||||||
|
var deserialized =
|
||||||
|
JsonConvert.DeserializeObject<JsonPatchDocument<JsonPropertyDTO>>(serialized);
|
||||||
|
|
||||||
|
deserialized.ApplyTo(doc);
|
||||||
|
|
||||||
|
Assert.Equal(null, doc.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Add_OnApplyFromJson_RespectsInheritedJsonPropertyNameOnJsonDocument()
|
||||||
|
{
|
||||||
|
var doc = new JsonPropertyWithInheritanceDTO()
|
||||||
|
{
|
||||||
|
Name = "InitialName"
|
||||||
|
};
|
||||||
|
|
||||||
|
// serialization should serialize to "AnotherName"
|
||||||
|
var serialized = "[{\"value\":\"Kevin\",\"path\":\"/AnotherName\",\"op\":\"add\"}]";
|
||||||
|
var deserialized =
|
||||||
|
JsonConvert.DeserializeObject<JsonPatchDocument<JsonPropertyWithInheritanceDTO>>(serialized);
|
||||||
|
|
||||||
|
deserialized.ApplyTo(doc);
|
||||||
|
|
||||||
|
Assert.Equal("Kevin", doc.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Add_WithExpression_RespectsJsonPropertyName_ForInheritedModelProperty()
|
||||||
|
{
|
||||||
|
var patchDoc = new JsonPatchDocument<JsonPropertyWithInheritanceDTO>();
|
||||||
|
patchDoc.Add(p => p.Name, "John");
|
||||||
|
|
||||||
|
var serialized = JsonConvert.SerializeObject(patchDoc);
|
||||||
|
// serialized value should have "AnotherName" as path
|
||||||
|
// deserialize to a JsonPatchDocument<JsonPropertyWithAnotherNameDTO> to check
|
||||||
|
var deserialized =
|
||||||
|
JsonConvert.DeserializeObject<JsonPatchDocument<JsonPropertyWithAnotherNameDTO>>(serialized);
|
||||||
|
|
||||||
|
// get path
|
||||||
|
var pathToCheck = deserialized.Operations.First().path;
|
||||||
|
Assert.Equal(pathToCheck, "/anothername");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.JsonPatch
|
||||||
|
{
|
||||||
|
public class JsonPropertyDTO
|
||||||
|
{
|
||||||
|
[JsonProperty("AnotherName")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.JsonPatch
|
||||||
|
{
|
||||||
|
public class JsonPropertyWithAnotherNameDTO
|
||||||
|
{
|
||||||
|
public string AnotherName { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.JsonPatch
|
||||||
|
{
|
||||||
|
public class JsonPropertyWithInheritanceDTO : JsonPropertyWithInheritanceBaseDTO
|
||||||
|
{
|
||||||
|
public override string Name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class JsonPropertyWithInheritanceBaseDTO
|
||||||
|
{
|
||||||
|
[JsonProperty("AnotherName")]
|
||||||
|
public abstract string Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue