-Added a special case to correctly deserialize Version class

-Changed Silverlight and Windows Phone assemblies in NuGet to be strong named
-Changed CamelCasePropertyNamesContractResolver to improve camel casing property names
-Fixed QuoteChar not being used when writing DateTimes, TimeSpans, Uris and Guids
This commit is contained in:
James Newton-King
2012-11-04 14:44:55 +13:00
parent b51b3aa20a
commit c06c7b8aae
13 changed files with 151 additions and 46 deletions
+3 -7
View File
@@ -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}
-3
View File
@@ -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.
@@ -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<Version>(reportJSON);
string reportJSON2 = JsonConvert.SerializeObject(report2);
Assert.AreEqual(reportJSON, reportJSON2);
}
}
}
@@ -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
}
}
@@ -274,6 +274,7 @@
<Compile Include="TestObjects\UserNullable.cs" />
<Compile Include="Utilities\DynamicReflectionDelegateFactoryTests.cs" />
<Compile Include="Utilities\ReflectionUtilsTests.cs" />
<Compile Include="Utilities\StringUtilsTests.cs" />
</ItemGroup>
<ItemGroup>
<Service Include="{3259AA49-8AA1-44D3-9025-A0B520596A8C}" />
@@ -293,6 +293,7 @@
<Compile Include="TestObjects\UserNullable.cs" />
<Compile Include="Utilities\DynamicReflectionDelegateFactoryTests.cs" />
<Compile Include="Utilities\ReflectionUtilsTests.cs" />
<Compile Include="Utilities\StringUtilsTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Newtonsoft.Json\Newtonsoft.Json.csproj">
@@ -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
@@ -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"));
}
}
}
+34 -12
View File
@@ -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
/// <param name="format">The format the date will be converted to.</param>
/// <returns>A JSON string representation of the <see cref="DateTimeOffset"/>.</returns>
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
/// <param name="value">The value to convert.</param>
/// <returns>A JSON string representation of the <see cref="Guid"/>.</returns>
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;
}
/// <summary>
@@ -504,7 +516,12 @@ namespace Newtonsoft.Json
/// <returns>A JSON string representation of the <see cref="TimeSpan"/>.</returns>
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);
}
/// <summary>
@@ -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);
}
/// <summary>
+5 -5
View File
@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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
@@ -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)]
@@ -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;
}
+16 -10
View File
@@ -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)