* 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.
|
||||
// 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.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNetCore.JsonPatch.Helpers
|
||||
{
|
||||
|
|
@ -51,11 +54,13 @@ namespace Microsoft.AspNetCore.JsonPatch.Helpers
|
|||
if (ContinueWithSubPath(memberExpression.Expression.NodeType, false))
|
||||
{
|
||||
var left = GetPath(memberExpression.Expression, false);
|
||||
return left + "/" + memberExpression.Member.Name;
|
||||
// Get property name, respecting JsonProperty attribute
|
||||
return left + "/" + GetPropertyNameFromMemberExpression(memberExpression);
|
||||
}
|
||||
else
|
||||
{
|
||||
return memberExpression.Member.Name;
|
||||
// Get property name, respecting JsonProperty attribute
|
||||
return GetPropertyNameFromMemberExpression(memberExpression);
|
||||
}
|
||||
case ExpressionType.Parameter:
|
||||
// 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)
|
||||
{
|
||||
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