-Added support for extension data names to NamingStrategy
-Added ProcessExtensionDataNames to NamingStrategy
This commit is contained in:
@@ -30,6 +30,7 @@ using System.Text;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Tests.TestObjects;
|
||||
using Newtonsoft.Json.Tests.TestObjects.Organization;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
#if DNXCORE50
|
||||
using Xunit;
|
||||
using Test = Xunit.FactAttribute;
|
||||
@@ -312,6 +313,15 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
}
|
||||
}
|
||||
|
||||
[JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy), NamingStrategyParameters = new object[] { true, true, true })]
|
||||
public class ExtensionDataWithNamingStrategyTestClass
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonExtensionData]
|
||||
internal IDictionary<string, JToken> ExtensionData { get; set; }
|
||||
}
|
||||
|
||||
public class JObjectExtensionDataTestClass
|
||||
{
|
||||
public string Name { get; set; }
|
||||
@@ -371,6 +381,158 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
Assert.AreEqual(7, c.ExtensionData.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionDataTest_DeserializeWithNamingStrategy()
|
||||
{
|
||||
string json = @"{
|
||||
""Ints"": [1,2,3],
|
||||
""Ignored"": [1,2,3],
|
||||
""Readonly"": ""Readonly"",
|
||||
""Name"": ""Actually set!"",
|
||||
""CustomName"": ""Wrong name!"",
|
||||
""GetPrivate"": true,
|
||||
""GetOnly"": true,
|
||||
""NewValueSimple"": true,
|
||||
""NewValueComplex"": [1,2,3]
|
||||
}";
|
||||
|
||||
ExtensionDataTestClass c = JsonConvert.DeserializeObject<ExtensionDataTestClass>(json, new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = new DefaultContractResolver
|
||||
{
|
||||
NamingStrategy = new CamelCaseNamingStrategy
|
||||
{
|
||||
ProcessExtensionDataNames = true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Assert.AreEqual("Actually set!", c.Name);
|
||||
Assert.AreEqual(4, c.Ints.Count);
|
||||
|
||||
Assert.AreEqual("Readonly", (string)c.ExtensionData["Readonly"]);
|
||||
Assert.AreEqual("Wrong name!", (string)c.ExtensionData["CustomName"]);
|
||||
Assert.AreEqual(true, (bool)c.ExtensionData["GetPrivate"]);
|
||||
Assert.AreEqual(true, (bool)c.ExtensionData["GetOnly"]);
|
||||
Assert.AreEqual(true, (bool)c.ExtensionData["NewValueSimple"]);
|
||||
Assert.IsTrue(JToken.DeepEquals(new JArray(1, 2, 3), c.ExtensionData["NewValueComplex"]));
|
||||
Assert.IsTrue(JToken.DeepEquals(new JArray(1, 2, 3), c.ExtensionData["Ignored"]));
|
||||
|
||||
Assert.AreEqual(7, c.ExtensionData.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionDataTest_SerializeWithNamingStrategy_Enabled()
|
||||
{
|
||||
ExtensionDataTestClass c = new ExtensionDataTestClass()
|
||||
{
|
||||
ExtensionData = new Dictionary<string, JToken>
|
||||
{
|
||||
["TestValue1"] = 1,
|
||||
["alreadyCamelCase"] = new JObject
|
||||
{
|
||||
["NotProcessed"] = true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
string json = JsonConvert.SerializeObject(c, new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = new DefaultContractResolver
|
||||
{
|
||||
NamingStrategy = new CamelCaseNamingStrategy
|
||||
{
|
||||
ProcessExtensionDataNames = true
|
||||
}
|
||||
},
|
||||
Formatting = Formatting.Indented
|
||||
});
|
||||
|
||||
StringAssert.AreEqual(@"{
|
||||
""readonly"": ""Readonly"",
|
||||
""name"": null,
|
||||
""custom_name"": null,
|
||||
""getPrivate"": false,
|
||||
""getOnly"": true,
|
||||
""ints"": [
|
||||
0
|
||||
],
|
||||
""testValue1"": 1,
|
||||
""alreadyCamelCase"": {
|
||||
""NotProcessed"": true
|
||||
}
|
||||
}", json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionDataTest_SerializeWithNamingStrategy_Disabled()
|
||||
{
|
||||
ExtensionDataTestClass c = new ExtensionDataTestClass()
|
||||
{
|
||||
ExtensionData = new Dictionary<string, JToken>
|
||||
{
|
||||
["TestValue1"] = 1,
|
||||
["alreadyCamelCase"] = new JObject
|
||||
{
|
||||
["NotProcessed"] = true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
string json = JsonConvert.SerializeObject(c, new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver
|
||||
{
|
||||
NamingStrategy = new Newtonsoft.Json.Serialization.CamelCaseNamingStrategy()
|
||||
},
|
||||
Formatting = Formatting.Indented
|
||||
});
|
||||
|
||||
StringAssert.AreEqual(@"{
|
||||
""readonly"": ""Readonly"",
|
||||
""name"": null,
|
||||
""custom_name"": null,
|
||||
""getPrivate"": false,
|
||||
""getOnly"": true,
|
||||
""ints"": [
|
||||
0
|
||||
],
|
||||
""TestValue1"": 1,
|
||||
""alreadyCamelCase"": {
|
||||
""NotProcessed"": true
|
||||
}
|
||||
}", json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionDataTest_SerializeWithNamingStrategyAttribute()
|
||||
{
|
||||
ExtensionDataWithNamingStrategyTestClass c = new ExtensionDataWithNamingStrategyTestClass()
|
||||
{
|
||||
ExtensionData = new Dictionary<string, JToken>
|
||||
{
|
||||
["TestValue1"] = 1,
|
||||
["alreadyCamelCase"] = new JObject
|
||||
{
|
||||
["NotProcessed"] = true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
string json = JsonConvert.SerializeObject(c, new JsonSerializerSettings
|
||||
{
|
||||
Formatting = Formatting.Indented
|
||||
});
|
||||
|
||||
StringAssert.AreEqual(@"{
|
||||
""name"": null,
|
||||
""testValue1"": 1,
|
||||
""alreadyCamelCase"": {
|
||||
""NotProcessed"": true
|
||||
}
|
||||
}", json);
|
||||
}
|
||||
|
||||
[JsonObject(MemberSerialization.OptIn)]
|
||||
public class MyClass
|
||||
{
|
||||
|
||||
@@ -23,6 +23,25 @@ namespace Newtonsoft.Json.Serialization
|
||||
OverrideSpecifiedNames = overrideSpecifiedNames;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CamelCaseNamingStrategy"/> class.
|
||||
/// </summary>
|
||||
/// <param name="processDictionaryKeys">
|
||||
/// A flag indicating whether dictionary keys should be processed.
|
||||
/// </param>
|
||||
/// <param name="overrideSpecifiedNames">
|
||||
/// A flag indicating whether explicitly specified property names should be processed,
|
||||
/// e.g. a property name customized with a <see cref="JsonPropertyAttribute"/>.
|
||||
/// </param>
|
||||
/// <param name="processExtensionDataNames">
|
||||
/// A flag indicating whether extension data names should be processed.
|
||||
/// </param>
|
||||
public CamelCaseNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames, bool processExtensionDataNames)
|
||||
: this(processDictionaryKeys, overrideSpecifiedNames)
|
||||
{
|
||||
ProcessExtensionDataNames = processExtensionDataNames;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CamelCaseNamingStrategy"/> class.
|
||||
/// </summary>
|
||||
|
||||
@@ -398,12 +398,26 @@ namespace Newtonsoft.Json.Serialization
|
||||
contract.MemberSerialization = JsonTypeReflector.GetObjectMemberSerialization(contract.NonNullableUnderlyingType, ignoreSerializableAttribute);
|
||||
contract.Properties.AddRange(CreateProperties(contract.NonNullableUnderlyingType, contract.MemberSerialization));
|
||||
|
||||
Func<string, string> extensionDataNameResolver = null;
|
||||
|
||||
JsonObjectAttribute attribute = JsonTypeReflector.GetCachedAttribute<JsonObjectAttribute>(contract.NonNullableUnderlyingType);
|
||||
if (attribute != null)
|
||||
{
|
||||
contract.ItemRequired = attribute._itemRequired;
|
||||
if (attribute.NamingStrategyType != null)
|
||||
{
|
||||
NamingStrategy namingStrategy = JsonTypeReflector.GetContainerNamingStrategy(attribute);
|
||||
extensionDataNameResolver = s => namingStrategy.GetDictionaryKey(s);
|
||||
}
|
||||
}
|
||||
|
||||
if (extensionDataNameResolver == null)
|
||||
{
|
||||
extensionDataNameResolver = ResolveExtensionDataName;
|
||||
}
|
||||
|
||||
contract.ExtensionDataNameResolver = extensionDataNameResolver;
|
||||
|
||||
if (contract.IsInstantiable)
|
||||
{
|
||||
ConstructorInfo overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType);
|
||||
@@ -1604,6 +1618,21 @@ namespace Newtonsoft.Json.Serialization
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the name of the extension data. By default no changes are made to extension data names.
|
||||
/// </summary>
|
||||
/// <param name="extensionDataName">Name of the extension data.</param>
|
||||
/// <returns>Resolved name of the extension data.</returns>
|
||||
protected virtual string ResolveExtensionDataName(string extensionDataName)
|
||||
{
|
||||
if (NamingStrategy != null)
|
||||
{
|
||||
return NamingStrategy.GetExtensionDataName(extensionDataName);
|
||||
}
|
||||
|
||||
return extensionDataName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the key of the dictionary. By default <see cref="ResolvePropertyName"/> is used to resolve dictionary keys.
|
||||
/// </summary>
|
||||
|
||||
@@ -158,6 +158,12 @@ namespace Newtonsoft.Json.Serialization
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the extension data name resolver.
|
||||
/// </summary>
|
||||
/// <value>The extension data name resolver.</value>
|
||||
public Func<string, string> ExtensionDataNameResolver { get; set; }
|
||||
|
||||
internal bool ExtensionDataIsJToken;
|
||||
private bool? _hasRequiredOrDefaultValueProperties;
|
||||
private ConstructorInfo _parametrizedConstructor;
|
||||
|
||||
@@ -496,6 +496,10 @@ namespace Newtonsoft.Json.Serialization
|
||||
bool escape;
|
||||
string propertyName = GetPropertyName(writer, e.Key, keyContract, out escape);
|
||||
|
||||
propertyName = (contract.ExtensionDataNameResolver != null)
|
||||
? contract.ExtensionDataNameResolver(propertyName)
|
||||
: propertyName;
|
||||
|
||||
if (ShouldWriteReference(e.Value, null, valueContract, contract, member))
|
||||
{
|
||||
writer.WritePropertyName(propertyName);
|
||||
|
||||
@@ -11,6 +11,12 @@
|
||||
/// </summary>
|
||||
public bool ProcessDictionaryKeys { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A flag indicating whether extension data names should be processed.
|
||||
/// Defaults to <c>false</c>.
|
||||
/// </summary>
|
||||
public bool ProcessExtensionDataNames { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A flag indicating whether explicitly specified property names,
|
||||
/// e.g. a property name customized with a <see cref="JsonPropertyAttribute"/>, should be processed.
|
||||
@@ -34,6 +40,21 @@
|
||||
return ResolvePropertyName(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the serialized name for a given extension data name.
|
||||
/// </summary>
|
||||
/// <param name="name">The initial extension data name.</param>
|
||||
/// <returns>The serialized extension data name.</returns>
|
||||
public virtual string GetExtensionDataName(string name)
|
||||
{
|
||||
if (!ProcessExtensionDataNames)
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
return ResolvePropertyName(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the serialized key for a given dictionary key.
|
||||
/// </summary>
|
||||
|
||||
@@ -23,6 +23,25 @@ namespace Newtonsoft.Json.Serialization
|
||||
OverrideSpecifiedNames = overrideSpecifiedNames;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SnakeCaseNamingStrategy"/> class.
|
||||
/// </summary>
|
||||
/// <param name="processDictionaryKeys">
|
||||
/// A flag indicating whether dictionary keys should be processed.
|
||||
/// </param>
|
||||
/// <param name="overrideSpecifiedNames">
|
||||
/// A flag indicating whether explicitly specified property names should be processed,
|
||||
/// e.g. a property name customized with a <see cref="JsonPropertyAttribute"/>.
|
||||
/// </param>
|
||||
/// <param name="processExtensionDataNames">
|
||||
/// A flag indicating whether extension data names should be processed.
|
||||
/// </param>
|
||||
public SnakeCaseNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames, bool processExtensionDataNames)
|
||||
: this(processDictionaryKeys, overrideSpecifiedNames)
|
||||
{
|
||||
ProcessExtensionDataNames = processExtensionDataNames;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SnakeCaseNamingStrategy"/> class.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user