diff --git a/Build/build.ps1 b/Build/build.ps1 index 2760a4cc..8d64dea3 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -19,13 +19,9 @@ @{Name = "Newtonsoft.Json"; TestsName = "Newtonsoft.Json.Tests"; Constants=""; FinalDir="Net40"; NuGetDir = "net40"; Framework="net-4.0"; Sign=$true}, @{Name = "Newtonsoft.Json.Portable"; TestsName = "Newtonsoft.Json.Tests.Portable"; Constants="PORTABLE"; FinalDir="Portable"; NuGetDir = "portable-net40+sl4+wp7+win8"; Framework="net-4.0"; Sign=$true}, @{Name = "Newtonsoft.Json.WinRT"; TestsName = $null; Constants="NETFX_CORE"; FinalDir="WinRT"; NuGetDir = "winrt45"; Framework="net-4.5"; Sign=$true}, - - # unsigned SL/WP - @{Name = "Newtonsoft.Json.WindowsPhone"; TestsName = $null; Constants="SILVERLIGHT;WINDOWS_PHONE"; FinalDir="WindowsPhone"; NuGetDir = "sl3-wp,sl4-windowsphone71"; Framework="net-4.0"; Sign=$false}, - @{Name = "Newtonsoft.Json.Silverlight"; TestsName = "Newtonsoft.Json.Tests.Silverlight"; Constants="SILVERLIGHT"; FinalDir="Silverlight"; NuGetDir = "sl4"; Framework="net-4.0"; Sign=$false}, - # signed SL/WP - @{Name = "Newtonsoft.Json.WindowsPhone"; TestsName = $null; Constants="SILVERLIGHT;WINDOWS_PHONE"; FinalDir="WindowsPhone\Signed"; NuGetDir = $null; Framework="net-4.0"; Sign=$true}, - @{Name = "Newtonsoft.Json.Silverlight"; TestsName = "Newtonsoft.Json.Tests.Silverlight"; Constants="SILVERLIGHT"; FinalDir="Silverlight\Signed"; NuGetDir = $null; Framework="net-4.0"; Sign=$true}, + + @{Name = "Newtonsoft.Json.WindowsPhone"; TestsName = $null; Constants="SILVERLIGHT;WINDOWS_PHONE"; FinalDir="WindowsPhone"; NuGetDir = "sl3-wp,sl4-windowsphone71"; Framework="net-4.0"; Sign=$true}, + @{Name = "Newtonsoft.Json.Silverlight"; TestsName = "Newtonsoft.Json.Tests.Silverlight"; Constants="SILVERLIGHT"; FinalDir="Silverlight"; NuGetDir = "sl4"; Framework="net-4.0"; Sign=$true}, @{Name = "Newtonsoft.Json.Net35"; TestsName = "Newtonsoft.Json.Tests.Net35"; Constants="NET35"; FinalDir="Net35"; NuGetDir = "net35"; Framework="net-2.0"; Sign=$true}, @{Name = "Newtonsoft.Json.Net20"; TestsName = "Newtonsoft.Json.Tests.Net20"; Constants="NET20"; FinalDir="Net20"; NuGetDir = "net20"; Framework="net-2.0"; Sign=$true} diff --git a/Doc/readme.txt b/Doc/readme.txt index 0cef8cf7..efeb677d 100644 --- a/Doc/readme.txt +++ b/Doc/readme.txt @@ -50,9 +50,6 @@ Json.NET comes in different versions for the various .NET frameworks. Notes: -The Silverlight and Windows Phone builds are not strong-named. -Use the assemblies in the Signed sub-directories for the strong-named versions. - Microsoft stopped support for the Compact Framework in Visual Studio 2010. For a Compact Framework 3.5 build download Json.NET 3.5. diff --git a/Src/Newtonsoft.Json.Tests/Converters/VersionConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/VersionConverterTests.cs index 6c1fb4fb..8d445d9c 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/VersionConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/VersionConverterTests.cs @@ -113,5 +113,18 @@ namespace Newtonsoft.Json.Tests.Converters DeserializeVersionClass("1.2.3", "2.3.4"); DeserializeVersionClass("1.2.3.4", "2.3.4.5"); } + + [Test] + public void RoundtripImplicitConverter() + { + var version = new Version(1, 0, 0, 0); + string reportJSON = JsonConvert.SerializeObject(version); + + //Test + Version report2 = JsonConvert.DeserializeObject(reportJSON); + string reportJSON2 = JsonConvert.SerializeObject(report2); + + Assert.AreEqual(reportJSON, reportJSON2); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs index f6850326..ecc808a0 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs @@ -854,5 +854,43 @@ _____'propertyName': NaN Assert.AreEqual("{'Blah':null}", sw.ToString()); } + +#if !NET20 + [Test] + public void QuoteChar() + { + StringWriter sw = new StringWriter(); + JsonTextWriter writer = new JsonTextWriter(sw); + writer.Formatting = Formatting.Indented; + writer.QuoteChar = '\''; + + writer.WriteStartArray(); + + writer.WriteValue(new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Utc)); + writer.WriteValue(new DateTimeOffset(2000, 1, 1, 1, 1, 1, TimeSpan.Zero)); + + writer.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat; + writer.WriteValue(new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Utc)); + writer.WriteValue(new DateTimeOffset(2000, 1, 1, 1, 1, 1, TimeSpan.Zero)); + + writer.WriteValue(new byte[] { 1, 2, 3 }); + writer.WriteValue(TimeSpan.Zero); + writer.WriteValue(new Uri("http://www.google.com/")); + writer.WriteValue(Guid.Empty); + + writer.WriteEnd(); + + Assert.AreEqual(@"[ + '2000-01-01T01:01:01Z', + '2000-01-01T01:01:01+00:00', + '\/Date(946688461000)\/', + '\/Date(946688461000+0000)\/', + 'AQID', + '00:00:00', + 'http://www.google.com/', + '00000000-0000-0000-0000-000000000000' +]", sw.ToString()); + } +#endif } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj index 55a53492..311db840 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.csproj @@ -274,6 +274,7 @@ + diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj index 72690e6e..eddf8a79 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj @@ -293,6 +293,7 @@ + diff --git a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs index 2bb55b06..e2e3fbf2 100644 --- a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs +++ b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs @@ -76,5 +76,5 @@ using System.Security; // by using the '*' as shown below: [assembly: AssemblyVersion("4.5.0.0")] #if !PocketPC -[assembly: AssemblyFileVersion("4.5.10.15503")] +[assembly: AssemblyFileVersion("4.5.10.15504")] #endif diff --git a/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs b/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs new file mode 100644 index 00000000..6ff45554 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; +using Newtonsoft.Json.Utilities; + +namespace Newtonsoft.Json.Tests.Utilities +{ + [TestFixture] + public class StringUtilsTests : TestFixtureBase + { + [Test] + public void ToCamelCaseTest() + { + Assert.AreEqual("urlValue", StringUtils.ToCamelCase("URLValue")); + Assert.AreEqual("url", StringUtils.ToCamelCase("URL")); + Assert.AreEqual("id", StringUtils.ToCamelCase("ID")); + 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("i Phone", StringUtils.ToCamelCase("I Phone")); + Assert.AreEqual(" IPhone", StringUtils.ToCamelCase(" IPhone")); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonConvert.cs b/Src/Newtonsoft.Json/JsonConvert.cs index 5d3aa920..2a651de8 100644 --- a/Src/Newtonsoft.Json/JsonConvert.cs +++ b/Src/Newtonsoft.Json/JsonConvert.cs @@ -110,7 +110,7 @@ namespace Newtonsoft.Json using (StringWriter writer = StringUtils.CreateStringWriter(64)) { - WriteDateTimeString(writer, updatedDateTime, updatedDateTime.GetUtcOffset(), updatedDateTime.Kind, format); + WriteDateTimeString(writer, updatedDateTime, updatedDateTime.GetUtcOffset(), updatedDateTime.Kind, format, '"'); return writer.ToString(); } } @@ -155,27 +155,33 @@ namespace Newtonsoft.Json /// The format the date will be converted to. /// A JSON string representation of the . public static string ToString(DateTimeOffset value, DateFormatHandling format) + { + return ToString(value, format, '"'); + } + + internal static string ToString(DateTimeOffset value, DateFormatHandling format, char quoteChar) { using (StringWriter writer = StringUtils.CreateStringWriter(64)) { - WriteDateTimeString(writer, (format == DateFormatHandling.IsoDateFormat) ? value.DateTime : value.UtcDateTime, value.Offset, DateTimeKind.Local, format); + WriteDateTimeString(writer, (format == DateFormatHandling.IsoDateFormat) ? value.DateTime : value.UtcDateTime, value.Offset, DateTimeKind.Local, format, quoteChar); return writer.ToString(); } } #endif - internal static void WriteDateTimeString(TextWriter writer, DateTime value, DateFormatHandling format) + internal static void WriteDateTimeString(TextWriter writer, DateTime value, DateFormatHandling format, char quoteChar) { - WriteDateTimeString(writer, value, value.GetUtcOffset(), value.Kind, format); + WriteDateTimeString(writer, value, value.GetUtcOffset(), value.Kind, format, quoteChar); } - internal static void WriteDateTimeString(TextWriter writer, DateTime value, TimeSpan offset, DateTimeKind kind, DateFormatHandling format) + internal static void WriteDateTimeString(TextWriter writer, DateTime value, TimeSpan offset, DateTimeKind kind, DateFormatHandling format, char quoteChar) { if (format == DateFormatHandling.MicrosoftDateFormat) { long javaScriptTicks = ConvertDateTimeToJavaScriptTicks(value, offset); - writer.Write(@"""\/Date("); + writer.Write(quoteChar); + writer.Write(@"\/Date("); writer.Write(javaScriptTicks); switch (kind) @@ -189,11 +195,12 @@ namespace Newtonsoft.Json break; } - writer.Write(@")\/"""); + writer.Write(@")\/"); + writer.Write(quoteChar); } else { - writer.Write(@""""); + writer.Write(quoteChar); writer.Write(value.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFF", CultureInfo.InvariantCulture)); switch (kind) @@ -207,7 +214,7 @@ namespace Newtonsoft.Json } - writer.Write(@""""); + writer.Write(quoteChar); } } @@ -485,6 +492,11 @@ namespace Newtonsoft.Json /// The value to convert. /// A JSON string representation of the . public static string ToString(Guid value) + { + return ToString(value, '"'); + } + + internal static string ToString(Guid value, char quoteChar) { string text = null; @@ -494,7 +506,7 @@ namespace Newtonsoft.Json text = value.ToString("D"); #endif - return '"' + text + '"'; + return quoteChar + text + quoteChar; } /// @@ -504,7 +516,12 @@ namespace Newtonsoft.Json /// A JSON string representation of the . public static string ToString(TimeSpan value) { - return '"' + value.ToString() + '"'; + return ToString(value, '"'); + } + + internal static string ToString(TimeSpan value, char quoteChar) + { + return ToString(value.ToString(), quoteChar); } /// @@ -517,7 +534,12 @@ namespace Newtonsoft.Json if (value == null) return Null; - return ToString(value.ToString()); + return ToString(value, '"'); + } + + internal static string ToString(Uri value, char quoteChar) + { + return ToString(value.ToString(), quoteChar); } /// diff --git a/Src/Newtonsoft.Json/JsonTextWriter.cs b/Src/Newtonsoft.Json/JsonTextWriter.cs index cb390a98..68ab5ebb 100644 --- a/Src/Newtonsoft.Json/JsonTextWriter.cs +++ b/Src/Newtonsoft.Json/JsonTextWriter.cs @@ -439,7 +439,7 @@ namespace Newtonsoft.Json { InternalWriteValue(JsonToken.Date); value = JsonConvert.EnsureDateTime(value, DateTimeZoneHandling); - JsonConvert.WriteDateTimeString(_writer, value, DateFormatHandling); + JsonConvert.WriteDateTimeString(_writer, value, DateFormatHandling, _quoteChar); } /// @@ -470,7 +470,7 @@ namespace Newtonsoft.Json public override void WriteValue(DateTimeOffset value) { InternalWriteValue(JsonToken.Date); - WriteValueInternal(JsonConvert.ToString(value, DateFormatHandling), JsonToken.Date); + WriteValueInternal(JsonConvert.ToString(value, DateFormatHandling, _quoteChar), JsonToken.Date); } #endif @@ -481,7 +481,7 @@ namespace Newtonsoft.Json public override void WriteValue(Guid value) { InternalWriteValue(JsonToken.String); - WriteValueInternal(JsonConvert.ToString(value), JsonToken.String); + WriteValueInternal(JsonConvert.ToString(value, _quoteChar), JsonToken.String); } /// @@ -491,7 +491,7 @@ namespace Newtonsoft.Json public override void WriteValue(TimeSpan value) { InternalWriteValue(JsonToken.String); - WriteValueInternal(JsonConvert.ToString(value), JsonToken.String); + WriteValueInternal(JsonConvert.ToString(value, _quoteChar), JsonToken.String); } /// @@ -507,7 +507,7 @@ namespace Newtonsoft.Json else { InternalWriteValue(JsonToken.String); - WriteValueInternal(JsonConvert.ToString(value), JsonToken.String); + WriteValueInternal(JsonConvert.ToString(value, _quoteChar), JsonToken.String); } } #endregion diff --git a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs index 6ecec87c..847575fc 100644 --- a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs +++ b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs @@ -90,7 +90,7 @@ using System.Security; // by using the '*' as shown below: [assembly: AssemblyVersion("4.5.0.0")] #if !PocketPC -[assembly: AssemblyFileVersion("4.5.10.15503")] +[assembly: AssemblyFileVersion("4.5.10.15504")] #endif [assembly: CLSCompliant(true)] diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs index 37051213..7b618097 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs @@ -365,15 +365,13 @@ namespace Newtonsoft.Json.Serialization if (attribute != null) contract.ItemRequired = attribute._itemRequired; + ConstructorInfo overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType); + // check if a JsonConstructorAttribute has been defined and use that - if (contract.NonNullableUnderlyingType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Any(c => c.IsDefined(typeof(JsonConstructorAttribute), true))) + if (overrideConstructor != null) { - ConstructorInfo constructor = GetAttributeConstructor(contract.NonNullableUnderlyingType); - if (constructor != null) - { - contract.OverrideConstructor = constructor; - contract.ConstructorParameters.AddRange(CreateConstructorParameters(constructor, contract.Properties)); - } + contract.OverrideConstructor = overrideConstructor; + contract.ConstructorParameters.AddRange(CreateConstructorParameters(overrideConstructor, contract.Properties)); } else if (contract.MemberSerialization == MemberSerialization.Fields) { @@ -405,6 +403,10 @@ namespace Newtonsoft.Json.Serialization else if (markedConstructors.Count == 1) return markedConstructors[0]; + // little hack to get Version objects to deserialize correctly + if (objectType == typeof(Version)) + return objectType.GetConstructor(new [] { typeof(int), typeof(int), typeof(int), typeof(int) }); + return null; } diff --git a/Src/Newtonsoft.Json/Utilities/StringUtils.cs b/Src/Newtonsoft.Json/Utilities/StringUtils.cs index 9e824794..abdcdfc2 100644 --- a/Src/Newtonsoft.Json/Utilities/StringUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/StringUtils.cs @@ -155,17 +155,23 @@ namespace Newtonsoft.Json.Utilities if (!char.IsUpper(s[0])) return s; - string camelCase = null; -#if !(NETFX_CORE || PORTABLE) - camelCase = char.ToLower(s[0], CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture); -#else - camelCase = char.ToLower(s[0]).ToString(); -#endif + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < s.Length; i++) + { + bool hasNext = (i + 1 < s.Length); + if ((i == 0 || !hasNext) || char.IsUpper(s[i + 1])) + { + char lowerCase = char.ToLower(s[i], CultureInfo.InvariantCulture); + sb.Append(lowerCase); + } + else + { + sb.Append(s.Substring(i)); + break; + } + } - if (s.Length > 1) - camelCase += s.Substring(1); - - return camelCase; + return sb.ToString(); } public static bool IsHighSurrogate(char c)