diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj
index 242d860f..4fa4587a 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net20.csproj
@@ -96,6 +96,7 @@
+
@@ -112,6 +113,7 @@
+
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj
index c848d910..a1f79940 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net35.csproj
@@ -139,6 +139,7 @@
+
@@ -155,6 +156,7 @@
+
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj
index 71333592..e9635d0e 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.csproj
@@ -257,6 +257,7 @@
+
@@ -271,6 +272,7 @@
+
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj
index 83b2bd64..2be23499 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj
@@ -132,6 +132,7 @@
+
@@ -146,6 +147,7 @@
+
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj
index 92d71a86..2eda8590 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.csproj
@@ -136,6 +136,7 @@
+
@@ -150,6 +151,7 @@
+
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
index 4ec9338d..5eb93ab5 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
@@ -262,6 +262,8 @@
+
+
diff --git a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs
index 7fdd7ec7..475cc910 100644
--- a/Src/Newtonsoft.Json.Tests/PerformanceTests.cs
+++ b/Src/Newtonsoft.Json.Tests/PerformanceTests.cs
@@ -503,7 +503,7 @@ If attributes are not mentioned, default values are used in each case.
{
for (int i = 0; i < interations; i++)
{
- using (StringWriter w = StringUtils.CreateStringWriter(StringUtils.GetLength(text) ?? 16))
+ using (StringWriter w = StringUtils.CreateStringWriter(text.Length))
{
char[] buffer = null;
JavaScriptUtils.WriteEscapedJavaScriptString(w, text, '"', true, JavaScriptUtils.DoubleQuoteCharEscapeFlags, StringEscapeHandling.Default, null, ref buffer);
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/CamelCaseNamingStrategyTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/CamelCaseNamingStrategyTests.cs
new file mode 100644
index 00000000..d0822a3b
--- /dev/null
+++ b/Src/Newtonsoft.Json.Tests/Serialization/CamelCaseNamingStrategyTests.cs
@@ -0,0 +1,327 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using Newtonsoft.Json.Serialization;
+#if NETFX_CORE
+using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
+using TestFixture = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestClassAttribute;
+using Test = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestMethodAttribute;
+#elif DNXCORE50
+using Xunit;
+using Test = Xunit.FactAttribute;
+using Assert = Newtonsoft.Json.Tests.XUnitAssert;
+#else
+using NUnit.Framework;
+#endif
+using Newtonsoft.Json.Tests.TestObjects;
+using Newtonsoft.Json.Linq;
+using System.Reflection;
+using Newtonsoft.Json.Utilities;
+
+namespace Newtonsoft.Json.Tests.Serialization
+{
+ [TestFixture]
+ public class CamelCaseNamingStrategyTests : TestFixtureBase
+ {
+ [Test]
+ public void JsonConvertSerializerSettings()
+ {
+ Person person = new Person();
+ person.BirthDate = new DateTime(2000, 11, 20, 23, 55, 44, DateTimeKind.Utc);
+ person.LastModified = new DateTime(2000, 11, 20, 23, 55, 44, DateTimeKind.Utc);
+ person.Name = "Name!";
+
+ DefaultContractResolver contractResolver = new DefaultContractResolver
+ {
+ NamingStrategy = new CamelCaseNamingStrategy()
+ };
+
+ string json = JsonConvert.SerializeObject(person, Formatting.Indented, new JsonSerializerSettings
+ {
+ ContractResolver = contractResolver
+ });
+
+ StringAssert.AreEqual(@"{
+ ""name"": ""Name!"",
+ ""birthDate"": ""2000-11-20T23:55:44Z"",
+ ""lastModified"": ""2000-11-20T23:55:44Z""
+}", json);
+
+ Person deserializedPerson = JsonConvert.DeserializeObject(json, new JsonSerializerSettings
+ {
+ ContractResolver = contractResolver
+ });
+
+ Assert.AreEqual(person.BirthDate, deserializedPerson.BirthDate);
+ Assert.AreEqual(person.LastModified, deserializedPerson.LastModified);
+ Assert.AreEqual(person.Name, deserializedPerson.Name);
+
+ json = JsonConvert.SerializeObject(person, Formatting.Indented);
+ StringAssert.AreEqual(@"{
+ ""Name"": ""Name!"",
+ ""BirthDate"": ""2000-11-20T23:55:44Z"",
+ ""LastModified"": ""2000-11-20T23:55:44Z""
+}", json);
+ }
+
+ [Test]
+ public void JTokenWriter_OverrideSpecifiedName()
+ {
+ JsonIgnoreAttributeOnClassTestClass ignoreAttributeOnClassTestClass = new JsonIgnoreAttributeOnClassTestClass();
+ ignoreAttributeOnClassTestClass.Field = int.MinValue;
+
+ DefaultContractResolver contractResolver = new DefaultContractResolver
+ {
+ NamingStrategy = new CamelCaseNamingStrategy
+ {
+ OverrideSpecifiedNames = true
+ }
+ };
+
+ JsonSerializer serializer = new JsonSerializer();
+ serializer.ContractResolver = contractResolver;
+
+ JTokenWriter writer = new JTokenWriter();
+
+ serializer.Serialize(writer, ignoreAttributeOnClassTestClass);
+
+ JObject o = (JObject)writer.Token;
+ JProperty p = o.Property("theField");
+
+ Assert.IsNotNull(p);
+ Assert.AreEqual(int.MinValue, (int)p.Value);
+ }
+
+ [Test]
+ public void BlogPostExample()
+ {
+ Product product = new Product
+ {
+ ExpiryDate = new DateTime(2010, 12, 20, 18, 1, 0, DateTimeKind.Utc),
+ Name = "Widget",
+ Price = 9.99m,
+ Sizes = new[] { "Small", "Medium", "Large" }
+ };
+
+ DefaultContractResolver contractResolver = new DefaultContractResolver
+ {
+ NamingStrategy = new CamelCaseNamingStrategy()
+ };
+
+ string json =
+ JsonConvert.SerializeObject(
+ product,
+ Formatting.Indented,
+ new JsonSerializerSettings { ContractResolver = contractResolver }
+ );
+
+ //{
+ // "name": "Widget",
+ // "expiryDate": "\/Date(1292868060000)\/",
+ // "price": 9.99,
+ // "sizes": [
+ // "Small",
+ // "Medium",
+ // "Large"
+ // ]
+ //}
+
+ StringAssert.AreEqual(@"{
+ ""name"": ""Widget"",
+ ""expiryDate"": ""2010-12-20T18:01:00Z"",
+ ""price"": 9.99,
+ ""sizes"": [
+ ""Small"",
+ ""Medium"",
+ ""Large""
+ ]
+}", json);
+ }
+
+#if !(NET35 || NET20 || PORTABLE40)
+ [Test]
+ public void DynamicCamelCasePropertyNames()
+ {
+ dynamic o = new TestDynamicObject();
+ o.Text = "Text!";
+ o.Integer = int.MaxValue;
+
+ DefaultContractResolver contractResolver = new DefaultContractResolver
+ {
+ NamingStrategy = new CamelCaseNamingStrategy
+ {
+ ProcessDictionaryKeys = true
+ }
+ };
+
+ string json = JsonConvert.SerializeObject(o, Formatting.Indented,
+ new JsonSerializerSettings
+ {
+ ContractResolver = contractResolver
+ });
+
+ StringAssert.AreEqual(@"{
+ ""explicit"": false,
+ ""text"": ""Text!"",
+ ""integer"": 2147483647,
+ ""int"": 0,
+ ""childObject"": null
+}", json);
+ }
+#endif
+
+ [Test]
+ public void DictionaryCamelCasePropertyNames_Disabled()
+ {
+ Dictionary values = new Dictionary
+ {
+ { "First", "Value1!" },
+ { "Second", "Value2!" }
+ };
+
+ DefaultContractResolver contractResolver = new DefaultContractResolver
+ {
+ NamingStrategy = new CamelCaseNamingStrategy()
+ };
+
+ string json = JsonConvert.SerializeObject(values, Formatting.Indented,
+ new JsonSerializerSettings
+ {
+ ContractResolver = contractResolver
+ });
+
+ StringAssert.AreEqual(@"{
+ ""First"": ""Value1!"",
+ ""Second"": ""Value2!""
+}", json);
+ }
+
+ [Test]
+ public void DictionaryCamelCasePropertyNames_Enabled()
+ {
+ Dictionary values = new Dictionary
+ {
+ { "First", "Value1!" },
+ { "Second", "Value2!" }
+ };
+
+ DefaultContractResolver contractResolver = new DefaultContractResolver
+ {
+ NamingStrategy = new CamelCaseNamingStrategy
+ {
+ ProcessDictionaryKeys = true
+ }
+ };
+
+ string json = JsonConvert.SerializeObject(values, Formatting.Indented,
+ new JsonSerializerSettings
+ {
+ ContractResolver = contractResolver
+ });
+
+ StringAssert.AreEqual(@"{
+ ""first"": ""Value1!"",
+ ""second"": ""Value2!""
+}", json);
+ }
+
+ public class PropertyAttributeNamingStrategyTestClass
+ {
+ [JsonProperty]
+ public string HasNoAttributeNamingStrategy { get; set; }
+
+ [JsonProperty(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
+ public string HasAttributeNamingStrategy { get; set; }
+ }
+
+ [Test]
+ public void JsonPropertyAttribute_NamingStrategyType()
+ {
+ PropertyAttributeNamingStrategyTestClass c = new PropertyAttributeNamingStrategyTestClass
+ {
+ HasNoAttributeNamingStrategy = "Value1!",
+ HasAttributeNamingStrategy = "Value2!"
+ };
+
+ string json = JsonConvert.SerializeObject(c, Formatting.Indented);
+
+ StringAssert.AreEqual(@"{
+ ""HasNoAttributeNamingStrategy"": ""Value1!"",
+ ""hasAttributeNamingStrategy"": ""Value2!""
+}", json);
+ }
+
+ [JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
+ public class ContainerAttributeNamingStrategyTestClass
+ {
+ public string Prop1 { get; set; }
+ public string Prop2 { get; set; }
+ [JsonProperty(NamingStrategyType = typeof(DefaultNamingStrategy))]
+ public string HasAttributeNamingStrategy { get; set; }
+ }
+
+ [Test]
+ public void JsonObjectAttribute_NamingStrategyType()
+ {
+ ContainerAttributeNamingStrategyTestClass c = new ContainerAttributeNamingStrategyTestClass
+ {
+ Prop1 = "Value1!",
+ Prop2 = "Value2!"
+ };
+
+ string json = JsonConvert.SerializeObject(c, Formatting.Indented);
+
+ StringAssert.AreEqual(@"{
+ ""prop1"": ""Value1!"",
+ ""prop2"": ""Value2!"",
+ ""HasAttributeNamingStrategy"": null
+}", json);
+ }
+
+ [JsonDictionary(NamingStrategyType = typeof(CamelCaseNamingStrategy), NamingStrategyParameters = new object[] { true, true })]
+ public class DictionaryAttributeNamingStrategyTestClass : Dictionary
+ {
+ }
+
+ [Test]
+ public void JsonDictionaryAttribute_NamingStrategyType()
+ {
+ DictionaryAttributeNamingStrategyTestClass c = new DictionaryAttributeNamingStrategyTestClass
+ {
+ ["Key1"] = "Value1!",
+ ["Key2"] = "Value2!"
+ };
+
+ string json = JsonConvert.SerializeObject(c, Formatting.Indented);
+
+ StringAssert.AreEqual(@"{
+ ""key1"": ""Value1!"",
+ ""key2"": ""Value2!""
+}", json);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/SnakeCaseNamingStrategyTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/SnakeCaseNamingStrategyTests.cs
new file mode 100644
index 00000000..9c254b7d
--- /dev/null
+++ b/Src/Newtonsoft.Json.Tests/Serialization/SnakeCaseNamingStrategyTests.cs
@@ -0,0 +1,327 @@
+#region License
+// Copyright (c) 2007 James Newton-King
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using Newtonsoft.Json.Serialization;
+#if NETFX_CORE
+using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
+using TestFixture = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestClassAttribute;
+using Test = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestMethodAttribute;
+#elif DNXCORE50
+using Xunit;
+using Test = Xunit.FactAttribute;
+using Assert = Newtonsoft.Json.Tests.XUnitAssert;
+#else
+using NUnit.Framework;
+#endif
+using Newtonsoft.Json.Tests.TestObjects;
+using Newtonsoft.Json.Linq;
+using System.Reflection;
+using Newtonsoft.Json.Utilities;
+
+namespace Newtonsoft.Json.Tests.Serialization
+{
+ [TestFixture]
+ public class SnakeCaseNamingStrategyTests : TestFixtureBase
+ {
+ [Test]
+ public void JsonConvertSerializerSettings()
+ {
+ Person person = new Person();
+ person.BirthDate = new DateTime(2000, 11, 20, 23, 55, 44, DateTimeKind.Utc);
+ person.LastModified = new DateTime(2000, 11, 20, 23, 55, 44, DateTimeKind.Utc);
+ person.Name = "Name!";
+
+ DefaultContractResolver contractResolver = new DefaultContractResolver
+ {
+ NamingStrategy = new SnakeCaseNamingStrategy()
+ };
+
+ string json = JsonConvert.SerializeObject(person, Formatting.Indented, new JsonSerializerSettings
+ {
+ ContractResolver = contractResolver
+ });
+
+ StringAssert.AreEqual(@"{
+ ""name"": ""Name!"",
+ ""birth_date"": ""2000-11-20T23:55:44Z"",
+ ""last_modified"": ""2000-11-20T23:55:44Z""
+}", json);
+
+ Person deserializedPerson = JsonConvert.DeserializeObject(json, new JsonSerializerSettings
+ {
+ ContractResolver = contractResolver
+ });
+
+ Assert.AreEqual(person.BirthDate, deserializedPerson.BirthDate);
+ Assert.AreEqual(person.LastModified, deserializedPerson.LastModified);
+ Assert.AreEqual(person.Name, deserializedPerson.Name);
+
+ json = JsonConvert.SerializeObject(person, Formatting.Indented);
+ StringAssert.AreEqual(@"{
+ ""Name"": ""Name!"",
+ ""BirthDate"": ""2000-11-20T23:55:44Z"",
+ ""LastModified"": ""2000-11-20T23:55:44Z""
+}", json);
+ }
+
+ [Test]
+ public void JTokenWriter_OverrideSpecifiedName()
+ {
+ JsonIgnoreAttributeOnClassTestClass ignoreAttributeOnClassTestClass = new JsonIgnoreAttributeOnClassTestClass();
+ ignoreAttributeOnClassTestClass.Field = int.MinValue;
+
+ DefaultContractResolver contractResolver = new DefaultContractResolver
+ {
+ NamingStrategy = new SnakeCaseNamingStrategy
+ {
+ OverrideSpecifiedNames = true
+ }
+ };
+
+ JsonSerializer serializer = new JsonSerializer();
+ serializer.ContractResolver = contractResolver;
+
+ JTokenWriter writer = new JTokenWriter();
+
+ serializer.Serialize(writer, ignoreAttributeOnClassTestClass);
+
+ JObject o = (JObject)writer.Token;
+ JProperty p = o.Property("the_field");
+
+ Assert.IsNotNull(p);
+ Assert.AreEqual(int.MinValue, (int)p.Value);
+ }
+
+ [Test]
+ public void BlogPostExample()
+ {
+ Product product = new Product
+ {
+ ExpiryDate = new DateTime(2010, 12, 20, 18, 1, 0, DateTimeKind.Utc),
+ Name = "Widget",
+ Price = 9.99m,
+ Sizes = new[] { "Small", "Medium", "Large" }
+ };
+
+ DefaultContractResolver contractResolver = new DefaultContractResolver
+ {
+ NamingStrategy = new SnakeCaseNamingStrategy()
+ };
+
+ string json =
+ JsonConvert.SerializeObject(
+ product,
+ Formatting.Indented,
+ new JsonSerializerSettings { ContractResolver = contractResolver }
+ );
+
+ //{
+ // "name": "Widget",
+ // "expiryDate": "\/Date(1292868060000)\/",
+ // "price": 9.99,
+ // "sizes": [
+ // "Small",
+ // "Medium",
+ // "Large"
+ // ]
+ //}
+
+ StringAssert.AreEqual(@"{
+ ""name"": ""Widget"",
+ ""expiry_date"": ""2010-12-20T18:01:00Z"",
+ ""price"": 9.99,
+ ""sizes"": [
+ ""Small"",
+ ""Medium"",
+ ""Large""
+ ]
+}", json);
+ }
+
+#if !(NET35 || NET20 || PORTABLE40)
+ [Test]
+ public void DynamicSnakeCasePropertyNames()
+ {
+ dynamic o = new TestDynamicObject();
+ o.Text = "Text!";
+ o.Integer = int.MaxValue;
+
+ DefaultContractResolver contractResolver = new DefaultContractResolver
+ {
+ NamingStrategy = new SnakeCaseNamingStrategy
+ {
+ ProcessDictionaryKeys = true
+ }
+ };
+
+ string json = JsonConvert.SerializeObject(o, Formatting.Indented,
+ new JsonSerializerSettings
+ {
+ ContractResolver = contractResolver
+ });
+
+ StringAssert.AreEqual(@"{
+ ""explicit"": false,
+ ""text"": ""Text!"",
+ ""integer"": 2147483647,
+ ""int"": 0,
+ ""child_object"": null
+}", json);
+ }
+#endif
+
+ [Test]
+ public void DictionarySnakeCasePropertyNames_Disabled()
+ {
+ Dictionary values = new Dictionary
+ {
+ { "First", "Value1!" },
+ { "Second", "Value2!" }
+ };
+
+ DefaultContractResolver contractResolver = new DefaultContractResolver
+ {
+ NamingStrategy = new SnakeCaseNamingStrategy()
+ };
+
+ string json = JsonConvert.SerializeObject(values, Formatting.Indented,
+ new JsonSerializerSettings
+ {
+ ContractResolver = contractResolver
+ });
+
+ StringAssert.AreEqual(@"{
+ ""First"": ""Value1!"",
+ ""Second"": ""Value2!""
+}", json);
+ }
+
+ [Test]
+ public void DictionarySnakeCasePropertyNames_Enabled()
+ {
+ Dictionary values = new Dictionary
+ {
+ { "First", "Value1!" },
+ { "Second", "Value2!" }
+ };
+
+ DefaultContractResolver contractResolver = new DefaultContractResolver
+ {
+ NamingStrategy = new SnakeCaseNamingStrategy
+ {
+ ProcessDictionaryKeys = true
+ }
+ };
+
+ string json = JsonConvert.SerializeObject(values, Formatting.Indented,
+ new JsonSerializerSettings
+ {
+ ContractResolver = contractResolver
+ });
+
+ StringAssert.AreEqual(@"{
+ ""first"": ""Value1!"",
+ ""second"": ""Value2!""
+}", json);
+ }
+
+ public class PropertyAttributeNamingStrategyTestClass
+ {
+ [JsonProperty]
+ public string HasNoAttributeNamingStrategy { get; set; }
+
+ [JsonProperty(NamingStrategyType = typeof(SnakeCaseNamingStrategy))]
+ public string HasAttributeNamingStrategy { get; set; }
+ }
+
+ [Test]
+ public void JsonPropertyAttribute_NamingStrategyType()
+ {
+ PropertyAttributeNamingStrategyTestClass c = new PropertyAttributeNamingStrategyTestClass
+ {
+ HasNoAttributeNamingStrategy = "Value1!",
+ HasAttributeNamingStrategy = "Value2!"
+ };
+
+ string json = JsonConvert.SerializeObject(c, Formatting.Indented);
+
+ StringAssert.AreEqual(@"{
+ ""HasNoAttributeNamingStrategy"": ""Value1!"",
+ ""has_attribute_naming_strategy"": ""Value2!""
+}", json);
+ }
+
+ [JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))]
+ public class ContainerAttributeNamingStrategyTestClass
+ {
+ public string Prop1 { get; set; }
+ public string Prop2 { get; set; }
+ [JsonProperty(NamingStrategyType = typeof(DefaultNamingStrategy))]
+ public string HasAttributeNamingStrategy { get; set; }
+ }
+
+ [Test]
+ public void JsonObjectAttribute_NamingStrategyType()
+ {
+ ContainerAttributeNamingStrategyTestClass c = new ContainerAttributeNamingStrategyTestClass
+ {
+ Prop1 = "Value1!",
+ Prop2 = "Value2!"
+ };
+
+ string json = JsonConvert.SerializeObject(c, Formatting.Indented);
+
+ StringAssert.AreEqual(@"{
+ ""prop1"": ""Value1!"",
+ ""prop2"": ""Value2!"",
+ ""HasAttributeNamingStrategy"": null
+}", json);
+ }
+
+ [JsonDictionary(NamingStrategyType = typeof(SnakeCaseNamingStrategy), NamingStrategyParameters = new object[] { true, true })]
+ public class DictionaryAttributeNamingStrategyTestClass : Dictionary
+ {
+ }
+
+ [Test]
+ public void JsonDictionaryAttribute_NamingStrategyType()
+ {
+ DictionaryAttributeNamingStrategyTestClass c = new DictionaryAttributeNamingStrategyTestClass
+ {
+ ["Key1"] = "Value1!",
+ ["Key2"] = "Value2!"
+ };
+
+ string json = JsonConvert.SerializeObject(c, Formatting.Indented);
+
+ StringAssert.AreEqual(@"{
+ ""key1"": ""Value1!"",
+ ""key2"": ""Value2!""
+}", json);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs b/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs
index 893776b1..bdc8e7e6 100644
--- a/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs
@@ -50,14 +50,53 @@ namespace Newtonsoft.Json.Tests.Utilities
Assert.AreEqual("i", StringUtils.ToCamelCase("I"));
Assert.AreEqual("", StringUtils.ToCamelCase(""));
Assert.AreEqual(null, StringUtils.ToCamelCase(null));
- Assert.AreEqual("iPhone", StringUtils.ToCamelCase("iPhone"));
Assert.AreEqual("person", StringUtils.ToCamelCase("Person"));
+ Assert.AreEqual("iPhone", StringUtils.ToCamelCase("iPhone"));
Assert.AreEqual("iPhone", StringUtils.ToCamelCase("IPhone"));
Assert.AreEqual("i Phone", StringUtils.ToCamelCase("I Phone"));
+ Assert.AreEqual("i Phone", StringUtils.ToCamelCase("I Phone"));
Assert.AreEqual(" IPhone", StringUtils.ToCamelCase(" IPhone"));
+ Assert.AreEqual(" IPhone ", StringUtils.ToCamelCase(" IPhone "));
Assert.AreEqual("isCIA", StringUtils.ToCamelCase("IsCIA"));
Assert.AreEqual("vmQ", StringUtils.ToCamelCase("VmQ"));
Assert.AreEqual("xml2Json", StringUtils.ToCamelCase("Xml2Json"));
+ Assert.AreEqual("snAkEcAsE", StringUtils.ToCamelCase("SnAkEcAsE"));
+ Assert.AreEqual("snA__kEcAsE", StringUtils.ToCamelCase("SnA__kEcAsE"));
+ Assert.AreEqual("snA__ kEcAsE", StringUtils.ToCamelCase("SnA__ kEcAsE"));
+ Assert.AreEqual("already_snake_case_ ", StringUtils.ToCamelCase("already_snake_case_ "));
+ Assert.AreEqual("isJSONProperty", StringUtils.ToCamelCase("IsJSONProperty"));
+ Assert.AreEqual("shoutinG_CASE", StringUtils.ToCamelCase("SHOUTING_CASE"));
+ Assert.AreEqual("9999-12-31T23:59:59.9999999Z", StringUtils.ToCamelCase("9999-12-31T23:59:59.9999999Z"));
+ Assert.AreEqual("hi!! This is text. Time to test.", StringUtils.ToCamelCase("Hi!! This is text. Time to test."));
+ }
+
+ [Test]
+ public void ToSnakeCaseTest()
+ {
+ Assert.AreEqual("url_value", StringUtils.ToSnakeCase("URLValue"));
+ Assert.AreEqual("url", StringUtils.ToSnakeCase("URL"));
+ Assert.AreEqual("id", StringUtils.ToSnakeCase("ID"));
+ Assert.AreEqual("i", StringUtils.ToSnakeCase("I"));
+ Assert.AreEqual("", StringUtils.ToSnakeCase(""));
+ Assert.AreEqual(null, StringUtils.ToSnakeCase(null));
+ Assert.AreEqual("person", StringUtils.ToSnakeCase("Person"));
+ Assert.AreEqual("i_phone", StringUtils.ToSnakeCase("iPhone"));
+ Assert.AreEqual("i_phone", StringUtils.ToSnakeCase("IPhone"));
+ Assert.AreEqual("i_phone", StringUtils.ToSnakeCase("I Phone"));
+ Assert.AreEqual("i_phone", StringUtils.ToSnakeCase("I Phone"));
+ Assert.AreEqual("i_phone", StringUtils.ToSnakeCase(" IPhone"));
+ Assert.AreEqual("i_phone", StringUtils.ToSnakeCase(" IPhone "));
+ Assert.AreEqual("is_cia", StringUtils.ToSnakeCase("IsCIA"));
+ Assert.AreEqual("vm_q", StringUtils.ToSnakeCase("VmQ"));
+ Assert.AreEqual("xml2_json", StringUtils.ToSnakeCase("Xml2Json"));
+ Assert.AreEqual("sn_ak_ec_as_e", StringUtils.ToSnakeCase("SnAkEcAsE"));
+ Assert.AreEqual("sn_a__k_ec_as_e", StringUtils.ToSnakeCase("SnA__kEcAsE"));
+ Assert.AreEqual("sn_a__k_ec_as_e", StringUtils.ToSnakeCase("SnA__ kEcAsE"));
+ Assert.AreEqual("already_snake_case_", StringUtils.ToSnakeCase("already_snake_case_ "));
+ Assert.AreEqual("is_json_property", StringUtils.ToSnakeCase("IsJSONProperty"));
+ Assert.AreEqual("shouting_case", StringUtils.ToSnakeCase("SHOUTING_CASE"));
+ Assert.AreEqual("9999-12-31_t23:59:59.9999999_z", StringUtils.ToSnakeCase("9999-12-31T23:59:59.9999999Z"));
+ Assert.AreEqual("hi!!_this_is_text._time_to_test.", StringUtils.ToSnakeCase("Hi!! This is text. Time to test."));
}
}
}
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs
index 9d2f822a..ceb38797 100644
--- a/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs
+++ b/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs
@@ -57,7 +57,7 @@ namespace Newtonsoft.Json.Converters
public string DateTimeFormat
{
get { return _dateTimeFormat ?? string.Empty; }
- set { _dateTimeFormat = StringUtils.NullEmptyString(value); }
+ set { _dateTimeFormat = (string.IsNullOrEmpty(value)) ? null : value; }
}
///
diff --git a/Src/Newtonsoft.Json/JsonContainerAttribute.cs b/Src/Newtonsoft.Json/JsonContainerAttribute.cs
index cfc1b58f..32bd975e 100644
--- a/Src/Newtonsoft.Json/JsonContainerAttribute.cs
+++ b/Src/Newtonsoft.Json/JsonContainerAttribute.cs
@@ -24,6 +24,7 @@
#endregion
using System;
+using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json
{
@@ -52,15 +53,15 @@ namespace Newtonsoft.Json
public string Description { get; set; }
///
- /// Gets the collection's items converter.
+ /// Gets or sets the collection's items converter.
///
/// The collection's items converter.
public Type ItemConverterType { get; set; }
///
- /// The parameter list to use when constructing the JsonConverter described by ItemConverterType.
+ /// The parameter list to use when constructing the described by ItemConverterType.
/// If null, the default constructor is used.
- /// When non-null, there must be a constructor defined in the JsonConverter that exactly matches the number,
+ /// When non-null, there must be a constructor defined in the that exactly matches the number,
/// order, and type of these parameters.
///
///
@@ -68,12 +69,49 @@ namespace Newtonsoft.Json
///
public object[] ItemConverterParameters { get; set; }
+ ///
+ /// Gets or sets the of the .
+ ///
+ /// The of the .
+ public Type NamingStrategyType
+ {
+ get { return _namingStrategyType; }
+ set
+ {
+ _namingStrategyType = value;
+ NamingStrategyInstance = null;
+ }
+ }
+
+ ///
+ /// The parameter list to use when constructing the described by NamingStrategyType.
+ /// If null, the default constructor is used.
+ /// When non-null, there must be a constructor defined in the that exactly matches the number,
+ /// order, and type of these parameters.
+ ///
+ ///
+ /// [JsonContainer(NamingStrategyType = typeof(MyNamingStrategy), NamingStrategyParameters = new object[] { 123, "Four" })]
+ ///
+ public object[] NamingStrategyParameters
+ {
+ get { return _namingStrategyParameters; }
+ set
+ {
+ _namingStrategyParameters = value;
+ NamingStrategyInstance = null;
+ }
+ }
+
+ internal NamingStrategy NamingStrategyInstance { get; set; }
+
// yuck. can't set nullable properties on an attribute in C#
// have to use this approach to get an unset default state
internal bool? _isReference;
internal bool? _itemIsReference;
internal ReferenceLoopHandling? _itemReferenceLoopHandling;
internal TypeNameHandling? _itemTypeNameHandling;
+ private Type _namingStrategyType;
+ private object[] _namingStrategyParameters;
///
/// Gets or sets a value that indicates whether to preserve object references.
diff --git a/Src/Newtonsoft.Json/JsonConverterAttribute.cs b/Src/Newtonsoft.Json/JsonConverterAttribute.cs
index fdafb3a4..aea831f6 100644
--- a/Src/Newtonsoft.Json/JsonConverterAttribute.cs
+++ b/Src/Newtonsoft.Json/JsonConverterAttribute.cs
@@ -38,16 +38,16 @@ namespace Newtonsoft.Json
private readonly Type _converterType;
///
- /// Gets the of the converter.
+ /// Gets the of the .
///
- /// The of the converter.
+ /// The of the .
public Type ConverterType
{
get { return _converterType; }
}
///
- /// The parameter list to use when constructing the JsonConverter described by ConverterType.
+ /// The parameter list to use when constructing the described by ConverterType.
/// If null, the default constructor is used.
///
public object[] ConverterParameters { get; private set; }
@@ -55,7 +55,7 @@ namespace Newtonsoft.Json
///
/// Initializes a new instance of the class.
///
- /// Type of the converter.
+ /// Type of the .
public JsonConverterAttribute(Type converterType)
{
if (converterType == null)
@@ -69,8 +69,8 @@ namespace Newtonsoft.Json
///
/// Initializes a new instance of the class.
///
- /// Type of the converter.
- /// Parameter list to use when constructing the JsonConverter. Can be null.
+ /// Type of the .
+ /// Parameter list to use when constructing the . Can be null.
public JsonConverterAttribute(Type converterType, params object[] converterParameters)
: this(converterType)
{
diff --git a/Src/Newtonsoft.Json/JsonPropertyAttribute.cs b/Src/Newtonsoft.Json/JsonPropertyAttribute.cs
index 6efe0ed7..0252ee44 100644
--- a/Src/Newtonsoft.Json/JsonPropertyAttribute.cs
+++ b/Src/Newtonsoft.Json/JsonPropertyAttribute.cs
@@ -24,6 +24,7 @@
#endregion
using System;
+using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json
{
@@ -48,15 +49,15 @@ namespace Newtonsoft.Json
internal TypeNameHandling? _itemTypeNameHandling;
///
- /// Gets or sets the converter used when serializing the property's collection items.
+ /// Gets or sets the used when serializing the property's collection items.
///
- /// The collection's items converter.
+ /// The collection's items .
public Type ItemConverterType { get; set; }
///
- /// The parameter list to use when constructing the JsonConverter described by ItemConverterType.
+ /// The parameter list to use when constructing the described by ItemConverterType.
/// If null, the default constructor is used.
- /// When non-null, there must be a constructor defined in the JsonConverter that exactly matches the number,
+ /// When non-null, there must be a constructor defined in the that exactly matches the number,
/// order, and type of these parameters.
///
///
@@ -64,6 +65,23 @@ namespace Newtonsoft.Json
///
public object[] ItemConverterParameters { get; set; }
+ ///
+ /// Gets or sets the of the .
+ ///
+ /// The of the .
+ public Type NamingStrategyType { get; set; }
+
+ ///
+ /// The parameter list to use when constructing the described by NamingStrategyType.
+ /// If null, the default constructor is used.
+ /// When non-null, there must be a constructor defined in the that exactly matches the number,
+ /// order, and type of these parameters.
+ ///
+ ///
+ /// [JsonProperty(NamingStrategyType = typeof(MyNamingStrategy), NamingStrategyParameters = new object[] { 123, "Four" })]
+ ///
+ public object[] NamingStrategyParameters { get; set; }
+
///
/// Gets or sets the null value handling used when serializing this property.
///
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj
index b63455d0..436a3683 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj
@@ -128,6 +128,8 @@
+
+
@@ -135,7 +137,9 @@
+
+
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj
index 09ea61c9..697a958c 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj
@@ -142,13 +142,17 @@
+
+
+
+
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net40.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net40.csproj
index e4cf0e32..2e41fe86 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net40.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net40.csproj
@@ -141,13 +141,17 @@
+
+
+
+
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj
index 2ff19dd6..56f6b0ce 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj
@@ -164,7 +164,9 @@
+
+
@@ -197,10 +199,12 @@
+
+
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Portable40.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Portable40.csproj
index 762db4d0..55c3494a 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Portable40.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Portable40.csproj
@@ -169,8 +169,10 @@
+
+
@@ -202,10 +204,12 @@
+
+
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
index d69978da..1055878b 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
@@ -168,8 +168,11 @@
+
+
+
@@ -179,6 +182,7 @@
+
diff --git a/Src/Newtonsoft.Json/Serialization/CamelCaseNamingStrategy.cs b/Src/Newtonsoft.Json/Serialization/CamelCaseNamingStrategy.cs
new file mode 100644
index 00000000..80d1b9ac
--- /dev/null
+++ b/Src/Newtonsoft.Json/Serialization/CamelCaseNamingStrategy.cs
@@ -0,0 +1,43 @@
+using Newtonsoft.Json.Utilities;
+
+namespace Newtonsoft.Json.Serialization
+{
+ ///
+ /// A camel case naming strategy.
+ ///
+ public class CamelCaseNamingStrategy : NamingStrategy
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// A flag indicating whether dictionary keys should be processed.
+ ///
+ ///
+ /// A flag indicating whether explicitly specified property names should be processed,
+ /// e.g. a property name customized with a .
+ ///
+ public CamelCaseNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames)
+ {
+ ProcessDictionaryKeys = processDictionaryKeys;
+ OverrideSpecifiedNames = overrideSpecifiedNames;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public CamelCaseNamingStrategy()
+ {
+ }
+
+ ///
+ /// Resolves the specified property name.
+ ///
+ /// The property name to resolve.
+ /// The resolved property name.
+ protected override string ResolvePropertyName(string name)
+ {
+ return StringUtils.ToCamelCase(name);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Serialization/CamelCasePropertyNamesContractResolver.cs b/Src/Newtonsoft.Json/Serialization/CamelCasePropertyNamesContractResolver.cs
index ea9ee82d..46085d58 100644
--- a/Src/Newtonsoft.Json/Serialization/CamelCasePropertyNamesContractResolver.cs
+++ b/Src/Newtonsoft.Json/Serialization/CamelCasePropertyNamesContractResolver.cs
@@ -41,17 +41,11 @@ namespace Newtonsoft.Json.Serialization
: base(true)
#pragma warning restore 612,618
{
- }
-
- ///
- /// Resolves the name of the property.
- ///
- /// Name of the property.
- /// The property name camel cased.
- protected override string ResolvePropertyName(string propertyName)
- {
- // lower case the first letter (or more) of the passed in name
- return StringUtils.ToCamelCase(propertyName);
+ NamingStrategy = new CamelCaseNamingStrategy
+ {
+ ProcessDictionaryKeys = true,
+ OverrideSpecifiedNames = true
+ };
}
}
}
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs
index 52c7b819..43a19c3e 100644
--- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs
+++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs
@@ -184,6 +184,12 @@ namespace Newtonsoft.Json.Serialization
public bool IgnoreSerializableAttribute { get; set; }
#endif
+ ///
+ /// Gets or sets the naming strategy used to resolve how property names and dictionary keys are serialized.
+ ///
+ /// The naming strategy used to resolve how property names and dictionary keys are serialized.
+ public NamingStrategy NamingStrategy { get; set; }
+
///
/// Initializes a new instance of the class.
///
@@ -737,7 +743,6 @@ namespace Newtonsoft.Json.Serialization
#if NET35
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Portability", "CA1903:UseOnlyApiFromTargetedFramework", MessageId = "System.Runtime.Serialization.DataContractAttribute.#get_IsReference()")]
#endif
-
private void InitializeContract(JsonContract contract)
{
JsonContainerAttribute containerAttribute = JsonTypeReflector.GetCachedAttribute(contract.NonNullableUnderlyingType);
@@ -905,7 +910,9 @@ namespace Newtonsoft.Json.Serialization
#endif
#if DOTNET
if (t.IsGenericType() && t.GetGenericTypeDefinition() == typeof(ConcurrentDictionary<,>))
+ {
return true;
+ }
#endif
return false;
@@ -937,7 +944,16 @@ namespace Newtonsoft.Json.Serialization
JsonDictionaryContract contract = new JsonDictionaryContract(objectType);
InitializeContract(contract);
- contract.DictionaryKeyResolver = ResolveDictionaryKey;
+ JsonContainerAttribute containerAttribute = JsonTypeReflector.GetAttribute(objectType);
+ if (containerAttribute?.NamingStrategyType != null)
+ {
+ NamingStrategy namingStrategy = JsonTypeReflector.GetContainerNamingStrategy(containerAttribute);
+ contract.DictionaryKeyResolver = s => namingStrategy.GetDictionaryKey(s);
+ }
+ else
+ {
+ contract.DictionaryKeyResolver = ResolveDictionaryKey;
+ }
ConstructorInfo overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType);
@@ -1065,7 +1081,17 @@ namespace Newtonsoft.Json.Serialization
JsonDynamicContract contract = new JsonDynamicContract(objectType);
InitializeContract(contract);
- contract.PropertyNameResolver = ResolvePropertyName;
+ JsonContainerAttribute containerAttribute = JsonTypeReflector.GetAttribute(objectType);
+ if (containerAttribute?.NamingStrategyType != null)
+ {
+ NamingStrategy namingStrategy = JsonTypeReflector.GetContainerNamingStrategy(containerAttribute);
+ contract.PropertyNameResolver = s => namingStrategy.GetDictionaryKey(s);
+ }
+ else
+ {
+ contract.PropertyNameResolver = ResolveDictionaryKey;
+ }
+
contract.Properties.AddRange(CreateProperties(objectType, MemberSerialization.OptOut));
return contract;
@@ -1386,22 +1412,50 @@ namespace Newtonsoft.Json.Serialization
JsonRequiredAttribute requiredAttribute = JsonTypeReflector.GetAttribute(attributeProvider);
string mappedName;
+ bool hasSpecifiedName;
if (propertyAttribute != null && propertyAttribute.PropertyName != null)
{
mappedName = propertyAttribute.PropertyName;
+ hasSpecifiedName = true;
}
#if !NET20
else if (dataMemberAttribute != null && dataMemberAttribute.Name != null)
{
mappedName = dataMemberAttribute.Name;
+ hasSpecifiedName = true;
}
#endif
else
{
mappedName = name;
+ hasSpecifiedName = false;
}
- property.PropertyName = ResolvePropertyName(mappedName);
+ JsonContainerAttribute containerAttribute = JsonTypeReflector.GetAttribute(declaringType);
+
+ NamingStrategy namingStrategy;
+ if (propertyAttribute?.NamingStrategyType != null)
+ {
+ namingStrategy = JsonTypeReflector.CreateNamingStrategyInstance(propertyAttribute.NamingStrategyType, propertyAttribute.NamingStrategyParameters);
+ }
+ else if (containerAttribute?.NamingStrategyType != null)
+ {
+ namingStrategy = JsonTypeReflector.GetContainerNamingStrategy(containerAttribute);
+ }
+ else
+ {
+ namingStrategy = NamingStrategy;
+ }
+
+ if (namingStrategy != null)
+ {
+ property.PropertyName = namingStrategy.GetPropertyName(mappedName, hasSpecifiedName);
+ }
+ else
+ {
+ property.PropertyName = ResolvePropertyName(mappedName);
+ }
+
property.UnderlyingName = name;
bool hasMemberAttribute = false;
@@ -1542,6 +1596,11 @@ namespace Newtonsoft.Json.Serialization
/// Resolved name of the property.
protected virtual string ResolvePropertyName(string propertyName)
{
+ if (NamingStrategy != null)
+ {
+ return NamingStrategy.GetPropertyName(propertyName, false);
+ }
+
return propertyName;
}
@@ -1552,6 +1611,11 @@ namespace Newtonsoft.Json.Serialization
/// Resolved key of the dictionary.
protected virtual string ResolveDictionaryKey(string dictionaryKey)
{
+ if (NamingStrategy != null)
+ {
+ return NamingStrategy.GetDictionaryKey(dictionaryKey);
+ }
+
return ResolvePropertyName(dictionaryKey);
}
diff --git a/Src/Newtonsoft.Json/Serialization/DefaultNamingStrategy.cs b/Src/Newtonsoft.Json/Serialization/DefaultNamingStrategy.cs
new file mode 100644
index 00000000..0f60780b
--- /dev/null
+++ b/Src/Newtonsoft.Json/Serialization/DefaultNamingStrategy.cs
@@ -0,0 +1,18 @@
+namespace Newtonsoft.Json.Serialization
+{
+ ///
+ /// The default naming strategy. Property names and dictionary keys are unchanged.
+ ///
+ public class DefaultNamingStrategy : NamingStrategy
+ {
+ ///
+ /// Resolves the specified property name.
+ ///
+ /// The property name to resolve.
+ /// The resolved property name.
+ protected override string ResolvePropertyName(string name)
+ {
+ return name;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs b/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs
index 0744b943..ae1b5349 100644
--- a/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs
+++ b/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs
@@ -56,8 +56,8 @@ namespace Newtonsoft.Json.Serialization
public const string ShouldSerializePrefix = "ShouldSerialize";
public const string SpecifiedPostfix = "Specified";
- private static readonly ThreadSafeStore> JsonConverterCreatorCache =
- new ThreadSafeStore>(GetJsonConverterCreator);
+ private static readonly ThreadSafeStore> CreatorCache =
+ new ThreadSafeStore>(GetCreator);
#if !(NET20 || DOTNET)
private static readonly ThreadSafeStore AssociatedMetadataTypesCache = new ThreadSafeStore(GetAssociateMetadataTypeFromAttribute);
@@ -162,10 +162,10 @@ namespace Newtonsoft.Json.Serialization
if (converterAttribute != null)
{
- Func