From 0db89bf5fac56e7afff1b40e6dc2446b8655ef01 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Sat, 2 Feb 2013 14:55:28 +1300 Subject: [PATCH] -Added FloatFormatHandling to JsonWriter/JsonSerializer/JsonSerializerSettings -Added DateFormatString to JsonWriter/JsonSerializer/JsonSerializerSettings -Changed StringEnumConverter to convert an empty string to null for nullable enums -Changed NaN and Infinity floating point values to be serialized as strings by default --- .../Converters/StringEnumConverterTests.cs | 13 ++ .../JsonTextWriterTest.cs | 147 +++++++++++++++++- .../Properties/AssemblyInfo.cs | 2 +- .../Serialization/JsonSerializerTest.cs | 122 +++++++++++++++ .../Serialization/TypeNameHandlingTests.cs | 21 +++ .../Converters/StringEnumConverter.cs | 13 +- Src/Newtonsoft.Json/FloatFormatHandling.cs | 9 ++ Src/Newtonsoft.Json/JsonConvert.cs | 58 +++++-- Src/Newtonsoft.Json/JsonSerializer.cs | 75 ++++++++- Src/Newtonsoft.Json/JsonSerializerSettings.cs | 29 ++++ Src/Newtonsoft.Json/JsonTextWriter.cs | 8 +- Src/Newtonsoft.Json/JsonWriter.cs | 21 +++ .../Newtonsoft.Json.Net20.csproj | 1 + .../Newtonsoft.Json.Net35.csproj | 1 + .../Newtonsoft.Json.Portable.csproj | 1 + .../Newtonsoft.Json.Silverlight.csproj | 1 + .../Newtonsoft.Json.WinRT.csproj | 1 + .../Newtonsoft.Json.WindowsPhone.csproj | 1 + Src/Newtonsoft.Json/Newtonsoft.Json.csproj | 1 + .../Properties/AssemblyInfo.cs | 2 +- .../Serialization/JsonSerializerProxy.cs | 18 +++ 21 files changed, 521 insertions(+), 24 deletions(-) create mode 100644 Src/Newtonsoft.Json/FloatFormatHandling.cs diff --git a/Src/Newtonsoft.Json.Tests/Converters/StringEnumConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/StringEnumConverterTests.cs index 8d31e4ce..71dcf77e 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/StringEnumConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/StringEnumConverterTests.cs @@ -321,5 +321,18 @@ namespace Newtonsoft.Json.Tests.Converters EnumContainer c = JsonConvert.DeserializeObject>(json, new StringEnumConverter { CamelCaseText = true }); Assert.AreEqual(FlagsTestEnum.First | FlagsTestEnum.Second, c.Enum); } + + [Test] + public void DeserializeEmptyStringIntoNullable() + { + string json = @"{ + ""StoreColor"": ""Red"", + ""NullableStoreColor1"": ""White"", + ""NullableStoreColor2"": """" +}"; + + EnumClass c = JsonConvert.DeserializeObject(json, new StringEnumConverter()); + Assert.IsNull(c.NullableStoreColor2); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs index b12c269f..0b9349e9 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs @@ -389,7 +389,7 @@ namespace Newtonsoft.Json.Tests } [Test] - public void FloatingPointNonFiniteNumbers() + public void FloatingPointNonFiniteNumbers_Symbol() { StringBuilder sb = new StringBuilder(); StringWriter sw = new StringWriter(sb); @@ -397,6 +397,7 @@ namespace Newtonsoft.Json.Tests using (JsonWriter jsonWriter = new JsonTextWriter(sw)) { jsonWriter.Formatting = Formatting.Indented; + jsonWriter.FloatFormatHandling = FloatFormatHandling.Symbol; jsonWriter.WriteStartArray(); jsonWriter.WriteValue(double.NaN); @@ -423,6 +424,115 @@ namespace Newtonsoft.Json.Tests Assert.AreEqual(expected, result); } + [Test] + public void FloatingPointNonFiniteNumbers_Zero() + { + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + + using (JsonWriter jsonWriter = new JsonTextWriter(sw)) + { + jsonWriter.Formatting = Formatting.Indented; + jsonWriter.FloatFormatHandling = FloatFormatHandling.Zero; + + jsonWriter.WriteStartArray(); + jsonWriter.WriteValue(double.NaN); + jsonWriter.WriteValue(double.PositiveInfinity); + jsonWriter.WriteValue(double.NegativeInfinity); + jsonWriter.WriteValue(float.NaN); + jsonWriter.WriteValue(float.PositiveInfinity); + jsonWriter.WriteValue(float.NegativeInfinity); + jsonWriter.WriteEndArray(); + + jsonWriter.Flush(); + } + + string expected = @"[ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 +]"; + string result = sb.ToString(); + + Assert.AreEqual(expected, result); + } + + [Test] + public void FloatingPointNonFiniteNumbers_String() + { + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + + using (JsonWriter jsonWriter = new JsonTextWriter(sw)) + { + jsonWriter.Formatting = Formatting.Indented; + jsonWriter.FloatFormatHandling = FloatFormatHandling.String; + + jsonWriter.WriteStartArray(); + jsonWriter.WriteValue(double.NaN); + jsonWriter.WriteValue(double.PositiveInfinity); + jsonWriter.WriteValue(double.NegativeInfinity); + jsonWriter.WriteValue(float.NaN); + jsonWriter.WriteValue(float.PositiveInfinity); + jsonWriter.WriteValue(float.NegativeInfinity); + jsonWriter.WriteEndArray(); + + jsonWriter.Flush(); + } + + string expected = @"[ + ""NaN"", + ""Infinity"", + ""-Infinity"", + ""NaN"", + ""Infinity"", + ""-Infinity"" +]"; + string result = sb.ToString(); + + Assert.AreEqual(expected, result); + } + + [Test] + public void FloatingPointNonFiniteNumbers_QuoteChar() + { + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + + using (JsonTextWriter jsonWriter = new JsonTextWriter(sw)) + { + jsonWriter.Formatting = Formatting.Indented; + jsonWriter.FloatFormatHandling = FloatFormatHandling.String; + jsonWriter.QuoteChar = '\''; + + jsonWriter.WriteStartArray(); + jsonWriter.WriteValue(double.NaN); + jsonWriter.WriteValue(double.PositiveInfinity); + jsonWriter.WriteValue(double.NegativeInfinity); + jsonWriter.WriteValue(float.NaN); + jsonWriter.WriteValue(float.PositiveInfinity); + jsonWriter.WriteValue(float.NegativeInfinity); + jsonWriter.WriteEndArray(); + + jsonWriter.Flush(); + } + + string expected = @"[ + 'NaN', + 'Infinity', + '-Infinity', + 'NaN', + 'Infinity', + '-Infinity' +]"; + string result = sb.ToString(); + + Assert.AreEqual(expected, result); + } + [Test] public void WriteRawInStart() { @@ -432,6 +542,7 @@ namespace Newtonsoft.Json.Tests using (JsonWriter jsonWriter = new JsonTextWriter(sw)) { jsonWriter.Formatting = Formatting.Indented; + jsonWriter.FloatFormatHandling = FloatFormatHandling.Symbol; jsonWriter.WriteRaw("[1,2,3,4,5]"); jsonWriter.WriteWhitespace(" "); @@ -457,6 +568,7 @@ namespace Newtonsoft.Json.Tests using (JsonWriter jsonWriter = new JsonTextWriter(sw)) { jsonWriter.Formatting = Formatting.Indented; + jsonWriter.FloatFormatHandling = FloatFormatHandling.Symbol; jsonWriter.WriteStartArray(); jsonWriter.WriteValue(double.NaN); @@ -569,6 +681,8 @@ namespace Newtonsoft.Json.Tests using (JsonWriter jsonWriter = new JsonTextWriter(sw)) { + jsonWriter.FloatFormatHandling = FloatFormatHandling.Symbol; + jsonWriter.WriteStartArray(); jsonWriter.WriteValue(0.0); @@ -642,6 +756,8 @@ namespace Newtonsoft.Json.Tests using (JsonTextWriter jsonWriter = new JsonTextWriter(sw)) { jsonWriter.Formatting = Formatting.Indented; + jsonWriter.FloatFormatHandling = FloatFormatHandling.Symbol; + Assert.AreEqual(Formatting.Indented, jsonWriter.Formatting); jsonWriter.Indentation = 5; @@ -936,6 +1052,10 @@ _____'propertyName': NaN 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.DateFormatString = "yyyy gg"; + 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/")); @@ -948,10 +1068,35 @@ _____'propertyName': NaN '2000-01-01T01:01:01+00:00', '\/Date(946688461000)\/', '\/Date(946688461000+0000)\/', + '2000 A.D.', + '2000 A.D.', 'AQID', '00:00:00', 'http://www.google.com/', '00000000-0000-0000-0000-000000000000' +]", sw.ToString()); + } + + [Test] + public void Culture() + { + StringWriter sw = new StringWriter(); + JsonTextWriter writer = new JsonTextWriter(sw); + writer.Formatting = Formatting.Indented; + writer.DateFormatString = "yyyy tt"; + writer.Culture = new CultureInfo("en-NZ"); + 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.WriteEnd(); + + Assert.AreEqual(@"[ + '2000 a.m.', + '2000 a.m.' ]", sw.ToString()); } #endif diff --git a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs index a4e61e61..1be61ecc 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.11.15729")] +[assembly: AssemblyFileVersion("4.5.11.15802")] #endif diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index 1791dc78..b900236f 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -7123,6 +7123,128 @@ Parameter name: value", Assert.AreEqual(TimeSpan.FromHours(9.5), dateTimeOffset.Offset); Assert.AreEqual("07/19/2012 14:30:00 +09:30", dateTimeOffset.ToString(CultureInfo.InvariantCulture)); } + + [Test] + public void DateFormatString() + { + IList dates = new List + { + new DateTime(2000, 12, 12, 12, 12, 12, DateTimeKind.Utc), + new DateTimeOffset(2000, 12, 12, 12, 12, 12, TimeSpan.FromHours(1)) + }; + + string json = JsonConvert.SerializeObject(dates, Formatting.Indented, new JsonSerializerSettings + { + DateFormatString = "yyyy tt", + Culture = new CultureInfo("en-NZ") + }); + + Assert.AreEqual(@"[ + ""2000 p.m."", + ""2000 p.m."" +]", json); + } + + [Test] + public void JsonSerializerDateFormatString() + { + IList dates = new List + { + new DateTime(2000, 12, 12, 12, 12, 12, DateTimeKind.Utc), + new DateTimeOffset(2000, 12, 12, 12, 12, 12, TimeSpan.FromHours(1)) + }; + + StringWriter sw = new StringWriter(); + JsonTextWriter jsonWriter = new JsonTextWriter(sw); + + JsonSerializer serializer = JsonSerializer.Create(new JsonSerializerSettings + { + DateFormatString = "yyyy tt", + Culture = new CultureInfo("en-NZ"), + Formatting = Formatting.Indented + }); + serializer.Serialize(jsonWriter, dates); + + Assert.IsNull(jsonWriter.DateFormatString); + Assert.AreEqual(CultureInfo.InvariantCulture, jsonWriter.Culture); + Assert.AreEqual(Formatting.None, jsonWriter.Formatting); + + string json = sw.ToString(); + + Assert.AreEqual(@"[ + ""2000 p.m."", + ""2000 p.m."" +]", json); + } + + [Test] + public void JsonSerializerStringEscapeHandling() + { + StringWriter sw = new StringWriter(); + JsonTextWriter jsonWriter = new JsonTextWriter(sw); + + JsonSerializer serializer = JsonSerializer.Create(new JsonSerializerSettings + { + StringEscapeHandling = StringEscapeHandling.EscapeHtml, + Formatting = Formatting.Indented + }); + serializer.Serialize(jsonWriter, new { html = "" }); + + Assert.AreEqual(StringEscapeHandling.Default, jsonWriter.StringEscapeHandling); + + string json = sw.ToString(); + + Assert.AreEqual(@"{ + ""html"": ""\u003chtml\u003e\u003c/html\u003e"" +}", json); + } + + [Test] + public void ReadStringFloatingPointSymbols() + { + string json = @"[ + 'NaN', + 'Infinity', + '-Infinity' +]"; + + IList floats = JsonConvert.DeserializeObject>(json); + Assert.AreEqual(float.NaN, floats[0]); + Assert.AreEqual(float.PositiveInfinity, floats[1]); + Assert.AreEqual(float.NegativeInfinity, floats[2]); + + IList doubles = JsonConvert.DeserializeObject>(json); + Assert.AreEqual(float.NaN, doubles[0]); + Assert.AreEqual(float.PositiveInfinity, doubles[1]); + Assert.AreEqual(float.NegativeInfinity, doubles[2]); + } + + [Test] + public void DefaultDateStringFormatVsUnsetDateStringFormat() + { + IDictionary dates = new Dictionary + { + {"DateTime-Unspecified", new DateTime(2000, 12, 12, 12, 12, 12, DateTimeKind.Unspecified)}, + {"DateTime-Utc", new DateTime(2000, 12, 12, 12, 12, 12, DateTimeKind.Utc)}, + {"DateTime-Local", new DateTime(2000, 12, 12, 12, 12, 12, DateTimeKind.Local)}, + {"DateTimeOffset-Zero", new DateTimeOffset(2000, 12, 12, 12, 12, 12, TimeSpan.Zero)}, + {"DateTimeOffset-Plus1", new DateTimeOffset(2000, 12, 12, 12, 12, 12, TimeSpan.FromHours(1))}, + {"DateTimeOffset-Plus15", new DateTimeOffset(2000, 12, 12, 12, 12, 12, TimeSpan.FromHours(1.5))} + }; + + string expected = JsonConvert.SerializeObject(dates, Formatting.Indented); + + Console.WriteLine(expected); + + string actual = JsonConvert.SerializeObject(dates, Formatting.Indented, new JsonSerializerSettings + { + DateFormatString = JsonSerializerSettings.DefaultDateFormatString + }); + + Console.WriteLine(expected); + + Assert.AreEqual(expected, actual); + } #endif #if !NET20 diff --git a/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs index 67c66689..e05d3b71 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs @@ -1455,6 +1455,27 @@ namespace Newtonsoft.Json.Tests.Serialization Assert.AreEqual(2, (int)o["MyProperty"]); } #endif + + [Test] + public void SerializeDeserialize_DictionaryContextContainsGuid_DeserializesItemAsGuid() + { + const string contextKey = "k1"; + var someValue = Guid.NewGuid(); + + Dictionary inputContext = new Dictionary(); + inputContext.Add(contextKey, someValue); + + JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings() + { + Formatting = Formatting.Indented, + TypeNameHandling = TypeNameHandling.All + }; + string serializedString = JsonConvert.SerializeObject(inputContext, jsonSerializerSettings); + + var deserializedObject = (Dictionary)JsonConvert.DeserializeObject(serializedString, jsonSerializerSettings); + + Assert.AreEqual(someValue, deserializedObject[contextKey]); + } } public class Message diff --git a/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs b/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs index c1f02694..022e4c6f 100644 --- a/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs +++ b/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs @@ -100,9 +100,8 @@ namespace Newtonsoft.Json.Converters /// The object value. public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - Type t = (ReflectionUtils.IsNullableType(objectType)) - ? Nullable.GetUnderlyingType(objectType) - : objectType; + bool isNullable = ReflectionUtils.IsNullableType(objectType); + Type t = isNullable ? Nullable.GetUnderlyingType(objectType) : objectType; if (reader.TokenType == JsonToken.Null) { @@ -114,10 +113,14 @@ namespace Newtonsoft.Json.Converters if (reader.TokenType == JsonToken.String) { + string enumText = reader.Value.ToString(); + if (enumText == string.Empty && isNullable) + return null; + var map = GetEnumNameMap(t); string resolvedEnumName; - map.TryGetBySecond(reader.Value.ToString(), out resolvedEnumName); - resolvedEnumName = resolvedEnumName ?? reader.Value.ToString(); + map.TryGetBySecond(enumText, out resolvedEnumName); + resolvedEnumName = resolvedEnumName ?? enumText; return Enum.Parse(t, resolvedEnumName, true); } diff --git a/Src/Newtonsoft.Json/FloatFormatHandling.cs b/Src/Newtonsoft.Json/FloatFormatHandling.cs new file mode 100644 index 00000000..ddb2a22a --- /dev/null +++ b/Src/Newtonsoft.Json/FloatFormatHandling.cs @@ -0,0 +1,9 @@ +namespace Newtonsoft.Json +{ + public enum FloatFormatHandling + { + String, + Symbol, + Zero + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonConvert.cs b/Src/Newtonsoft.Json/JsonConvert.cs index 7cf4ab85..fbed1d8c 100644 --- a/Src/Newtonsoft.Json/JsonConvert.cs +++ b/Src/Newtonsoft.Json/JsonConvert.cs @@ -155,23 +155,41 @@ 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, quoteChar); + WriteDateTimeOffsetString(writer, value, format, null, CultureInfo.InvariantCulture, '"'); return writer.ToString(); } } + + internal static void WriteDateTimeOffsetString(TextWriter writer, DateTimeOffset value, DateFormatHandling format, string formatString, CultureInfo culture, char quoteChar) + { + if (string.IsNullOrEmpty(formatString)) + { + WriteDateTimeString(writer, (format == DateFormatHandling.IsoDateFormat) ? value.DateTime : value.UtcDateTime, value.Offset, DateTimeKind.Local, format, quoteChar); + } + else + { + writer.Write(quoteChar); + writer.Write(value.ToString(formatString, culture)); + writer.Write(quoteChar); + } + } #endif - internal static void WriteDateTimeString(TextWriter writer, DateTime value, DateFormatHandling format, char quoteChar) + internal static void WriteDateTimeString(TextWriter writer, DateTime value, DateFormatHandling format, string formatString, CultureInfo culture, char quoteChar) { - WriteDateTimeString(writer, value, value.GetUtcOffset(), value.Kind, format, quoteChar); + if (string.IsNullOrEmpty(formatString)) + { + WriteDateTimeString(writer, value, value.GetUtcOffset(), value.Kind, format, quoteChar); + } + else + { + writer.Write(quoteChar); + writer.Write(value.ToString(formatString, culture)); + writer.Write(quoteChar); + } } internal static void WriteDateTimeString(TextWriter writer, DateTime value, TimeSpan offset, DateTimeKind kind, DateFormatHandling format, char quoteChar) @@ -201,7 +219,7 @@ namespace Newtonsoft.Json else { writer.Write(quoteChar); - writer.Write(value.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFF", CultureInfo.InvariantCulture)); + writer.Write(value.ToString(@"yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFF", CultureInfo.InvariantCulture)); switch (kind) { @@ -213,7 +231,6 @@ namespace Newtonsoft.Json break; } - writer.Write(quoteChar); } } @@ -429,6 +446,22 @@ namespace Newtonsoft.Json return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)); } + internal static string ToString(float value, FloatFormatHandling floatFormatHandling, char quoteChar) + { + return EnsureFloatFormat(value, EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)), floatFormatHandling, quoteChar); + } + + private static string EnsureFloatFormat(double value, string text, FloatFormatHandling floatFormatHandling, char quoteChar) + { + if (floatFormatHandling == FloatFormatHandling.Symbol || !(double.IsInfinity(value) || double.IsNaN(value))) + return text; + + if (floatFormatHandling == FloatFormatHandling.Zero) + return "0.0"; + + return quoteChar + text + quoteChar; + } + /// /// Converts the to its JSON string representation. /// @@ -439,6 +472,11 @@ namespace Newtonsoft.Json return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)); } + internal static string ToString(double value, FloatFormatHandling floatFormatHandling, char quoteChar) + { + return EnsureFloatFormat(value, EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)), floatFormatHandling, quoteChar); + } + private static string EnsureDecimalPlace(double value, string text) { if (double.IsNaN(value) || double.IsInfinity(value) || text.IndexOf('.') != -1 || text.IndexOf('E') != -1 || text.IndexOf('e') != -1) diff --git a/Src/Newtonsoft.Json/JsonSerializer.cs b/Src/Newtonsoft.Json/JsonSerializer.cs index c8813a73..babc6200 100644 --- a/Src/Newtonsoft.Json/JsonSerializer.cs +++ b/Src/Newtonsoft.Json/JsonSerializer.cs @@ -62,10 +62,14 @@ namespace Newtonsoft.Json private DateFormatHandling? _dateFormatHandling; private DateTimeZoneHandling? _dateTimeZoneHandling; private DateParseHandling? _dateParseHandling; + private FloatFormatHandling? _floatFormatHandling; + private StringEscapeHandling? _stringEscapeHandling; private CultureInfo _culture; private int? _maxDepth; private bool _maxDepthSet; private bool? _checkAdditionalContent; + private string _dateFormatString; + private bool _dateFormatStringSet; /// /// Occurs when the errors during serialization and deserialization. @@ -342,6 +346,28 @@ namespace Newtonsoft.Json set { _dateParseHandling = value; } } + public virtual FloatFormatHandling FloatFormatHandling + { + get { return _floatFormatHandling ?? JsonSerializerSettings.DefaultFloatFormatHandling; } + set { _floatFormatHandling = value; } + } + + public virtual StringEscapeHandling StringEscapeHandling + { + get { return _stringEscapeHandling ?? JsonSerializerSettings.DefaultStringEscapeHandling; } + set { _stringEscapeHandling = value; } + } + + public virtual string DateFormatString + { + get { return _dateFormatString ?? JsonSerializerSettings.DefaultDateFormatString; } + set + { + _dateFormatString = value; + _dateFormatStringSet = true; + } + } + /// /// Gets or sets the culture used when reading JSON. Defaults to . /// @@ -436,6 +462,10 @@ namespace Newtonsoft.Json jsonSerializer._dateFormatHandling = settings._dateFormatHandling; jsonSerializer._dateTimeZoneHandling = settings._dateTimeZoneHandling; jsonSerializer._dateParseHandling = settings._dateParseHandling; + jsonSerializer._dateFormatString = settings._dateFormatString; + jsonSerializer._dateFormatStringSet = settings._dateFormatStringSet; + jsonSerializer._floatFormatHandling = settings._floatFormatHandling; + jsonSerializer._stringEscapeHandling = settings._stringEscapeHandling; jsonSerializer._culture = settings._culture; jsonSerializer._maxDepth = settings._maxDepth; jsonSerializer._maxDepthSet = settings._maxDepthSet; @@ -537,23 +567,26 @@ namespace Newtonsoft.Json // set serialization options onto reader CultureInfo previousCulture = null; - if (_culture != null && reader.Culture != _culture) + if (_culture != null && !_culture.Equals(reader.Culture)) { previousCulture = reader.Culture; reader.Culture = _culture; } + DateTimeZoneHandling? previousDateTimeZoneHandling = null; if (_dateTimeZoneHandling != null && reader.DateTimeZoneHandling != _dateTimeZoneHandling) { previousDateTimeZoneHandling = reader.DateTimeZoneHandling; reader.DateTimeZoneHandling = _dateTimeZoneHandling.Value; } + DateParseHandling? previousDateParseHandling = null; if (_dateParseHandling != null && reader.DateParseHandling != _dateParseHandling) { previousDateParseHandling = reader.DateParseHandling; reader.DateParseHandling = _dateParseHandling.Value; } + int? previousMaxDepth = null; if (_maxDepthSet && reader.MaxDepth != _maxDepth) { @@ -610,19 +643,49 @@ namespace Newtonsoft.Json previousFormatting = jsonWriter.Formatting; jsonWriter.Formatting = _formatting.Value; } + DateFormatHandling? previousDateFormatHandling = null; if (_dateFormatHandling != null && jsonWriter.DateFormatHandling != _dateFormatHandling) { previousDateFormatHandling = jsonWriter.DateFormatHandling; jsonWriter.DateFormatHandling = _dateFormatHandling.Value; } + DateTimeZoneHandling? previousDateTimeZoneHandling = null; if (_dateTimeZoneHandling != null && jsonWriter.DateTimeZoneHandling != _dateTimeZoneHandling) { previousDateTimeZoneHandling = jsonWriter.DateTimeZoneHandling; jsonWriter.DateTimeZoneHandling = _dateTimeZoneHandling.Value; } - + + FloatFormatHandling? previousFloatFormatHandling = null; + if (_floatFormatHandling != null && jsonWriter.FloatFormatHandling != _floatFormatHandling) + { + previousFloatFormatHandling = jsonWriter.FloatFormatHandling; + jsonWriter.FloatFormatHandling = _floatFormatHandling.Value; + } + + StringEscapeHandling? previousStringEscapeHandling = null; + if (_stringEscapeHandling != null && jsonWriter.StringEscapeHandling != _stringEscapeHandling) + { + previousStringEscapeHandling = jsonWriter.StringEscapeHandling; + jsonWriter.StringEscapeHandling = _stringEscapeHandling.Value; + } + + CultureInfo previousCulture = null; + if (_culture != null && !_culture.Equals(jsonWriter.Culture)) + { + previousCulture = jsonWriter.Culture; + jsonWriter.Culture = _culture; + } + + string previousDateFormatString = null; + if (_dateFormatStringSet && jsonWriter.DateFormatString != _dateFormatString) + { + previousDateFormatString = jsonWriter.DateFormatString; + jsonWriter.DateFormatString = _dateFormatString; + } + JsonSerializerInternalWriter serializerWriter = new JsonSerializerInternalWriter(this); serializerWriter.Serialize(jsonWriter, value); @@ -633,6 +696,14 @@ namespace Newtonsoft.Json jsonWriter.DateFormatHandling = previousDateFormatHandling.Value; if (previousDateTimeZoneHandling != null) jsonWriter.DateTimeZoneHandling = previousDateTimeZoneHandling.Value; + if (previousFloatFormatHandling != null) + jsonWriter.FloatFormatHandling = previousFloatFormatHandling.Value; + if (previousStringEscapeHandling != null) + jsonWriter.StringEscapeHandling = previousStringEscapeHandling.Value; + if (_dateFormatStringSet) + jsonWriter.DateFormatString = previousDateFormatString; + if (previousCulture != null) + jsonWriter.Culture = previousCulture; } internal JsonConverter GetMatchingConverter(Type type) diff --git a/Src/Newtonsoft.Json/JsonSerializerSettings.cs b/Src/Newtonsoft.Json/JsonSerializerSettings.cs index c02872a9..2204d98b 100644 --- a/Src/Newtonsoft.Json/JsonSerializerSettings.cs +++ b/Src/Newtonsoft.Json/JsonSerializerSettings.cs @@ -52,17 +52,24 @@ namespace Newtonsoft.Json internal const DateFormatHandling DefaultDateFormatHandling = DateFormatHandling.IsoDateFormat; internal const DateTimeZoneHandling DefaultDateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind; internal const DateParseHandling DefaultDateParseHandling = DateParseHandling.DateTime; + internal const FloatFormatHandling DefaultFloatFormatHandling = FloatFormatHandling.String; + internal const StringEscapeHandling DefaultStringEscapeHandling = StringEscapeHandling.Default; internal static readonly CultureInfo DefaultCulture; internal const bool DefaultCheckAdditionalContent = false; + internal const string DefaultDateFormatString = @"yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"; internal Formatting? _formatting; internal DateFormatHandling? _dateFormatHandling; internal DateTimeZoneHandling? _dateTimeZoneHandling; internal DateParseHandling? _dateParseHandling; + internal FloatFormatHandling? _floatFormatHandling; + internal StringEscapeHandling? _stringEscapeHandling; internal CultureInfo _culture; internal bool? _checkAdditionalContent; internal int? _maxDepth; internal bool _maxDepthSet; + internal string _dateFormatString; + internal bool _dateFormatStringSet; /// /// Gets or sets how reference loops (e.g. a class referencing itself) is handled. @@ -161,6 +168,16 @@ namespace Newtonsoft.Json /// The context. public StreamingContext Context { get; set; } + public string DateFormatString + { + get { return _dateFormatString ?? DefaultDateFormatString; } + set + { + _dateFormatString = value; + _dateFormatStringSet = true; + } + } + /// /// Gets or sets the maximum depth allowed when reading JSON. Reading past this depth will throw a . /// @@ -213,6 +230,18 @@ namespace Newtonsoft.Json set { _dateParseHandling = value; } } + public FloatFormatHandling FloatFormatHandling + { + get { return _floatFormatHandling ?? DefaultFloatFormatHandling; } + set { _floatFormatHandling = value; } + } + + public StringEscapeHandling StringEscapeHandling + { + get { return _stringEscapeHandling ?? DefaultStringEscapeHandling; } + set { _stringEscapeHandling = value; } + } + /// /// Gets or sets the culture used when reading JSON. Defaults to . /// diff --git a/Src/Newtonsoft.Json/JsonTextWriter.cs b/Src/Newtonsoft.Json/JsonTextWriter.cs index 77533155..0f2e16f0 100644 --- a/Src/Newtonsoft.Json/JsonTextWriter.cs +++ b/Src/Newtonsoft.Json/JsonTextWriter.cs @@ -357,7 +357,7 @@ namespace Newtonsoft.Json public override void WriteValue(float value) { InternalWriteValue(JsonToken.Float); - WriteValueInternal(JsonConvert.ToString(value), JsonToken.Float); + WriteValueInternal(JsonConvert.ToString(value, FloatFormatHandling, QuoteChar), JsonToken.Float); } /// @@ -367,7 +367,7 @@ namespace Newtonsoft.Json public override void WriteValue(double value) { InternalWriteValue(JsonToken.Float); - WriteValueInternal(JsonConvert.ToString(value), JsonToken.Float); + WriteValueInternal(JsonConvert.ToString(value, FloatFormatHandling, QuoteChar), JsonToken.Float); } /// @@ -450,7 +450,7 @@ namespace Newtonsoft.Json { InternalWriteValue(JsonToken.Date); value = JsonConvert.EnsureDateTime(value, DateTimeZoneHandling); - JsonConvert.WriteDateTimeString(_writer, value, DateFormatHandling, _quoteChar); + JsonConvert.WriteDateTimeString(_writer, value, DateFormatHandling, DateFormatString, Culture, _quoteChar); } /// @@ -481,7 +481,7 @@ namespace Newtonsoft.Json public override void WriteValue(DateTimeOffset value) { InternalWriteValue(JsonToken.Date); - WriteValueInternal(JsonConvert.ToString(value, DateFormatHandling, _quoteChar), JsonToken.Date); + JsonConvert.WriteDateTimeOffsetString(_writer, value, DateFormatHandling, DateFormatString, Culture, _quoteChar); } #endif diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs index 3b1cad5a..b4300aee 100644 --- a/Src/Newtonsoft.Json/JsonWriter.cs +++ b/Src/Newtonsoft.Json/JsonWriter.cs @@ -210,6 +210,9 @@ namespace Newtonsoft.Json private DateFormatHandling _dateFormatHandling; private DateTimeZoneHandling _dateTimeZoneHandling; private StringEscapeHandling _stringEscapeHandling; + private FloatFormatHandling _floatFormatHandling; + private string _dateFormatString; + private CultureInfo _culture; /// /// Indicates how JSON text output is formatted. @@ -247,6 +250,24 @@ namespace Newtonsoft.Json set { _stringEscapeHandling = value; } } + public FloatFormatHandling FloatFormatHandling + { + get { return _floatFormatHandling; } + set { _floatFormatHandling = value; } + } + + public string DateFormatString + { + get { return _dateFormatString; } + set { _dateFormatString = value; } + } + + public CultureInfo Culture + { + get { return _culture ?? CultureInfo.InvariantCulture; } + set { _culture = value; } + } + /// /// Creates an instance of the JsonWriter class. /// diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj index ba2a7d1e..5f3418b4 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net20.csproj @@ -95,6 +95,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj index 85281869..a2edc5ce 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Net35.csproj @@ -107,6 +107,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj index fa32a3a1..f8e1b993 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Portable.csproj @@ -68,6 +68,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj index e74417e7..65c0b8d4 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj @@ -106,6 +106,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.WinRT.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.WinRT.csproj index 19c3c334..43a344a3 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.WinRT.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.WinRT.csproj @@ -136,6 +136,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.WindowsPhone.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.WindowsPhone.csproj index 220638f0..b5f31243 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.WindowsPhone.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.WindowsPhone.csproj @@ -79,6 +79,7 @@ + diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj index 756a6507..b651482e 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj @@ -104,6 +104,7 @@ + diff --git a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs index 8e95c4f0..ec881814 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.11.15729")] +[assembly: AssemblyFileVersion("4.5.11.15802")] #endif [assembly: CLSCompliant(true)] diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerProxy.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerProxy.cs index 4e4ce413..a7fff0d0 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerProxy.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerProxy.cs @@ -156,6 +156,24 @@ namespace Newtonsoft.Json.Serialization set { _serializer.DateParseHandling = value; } } + public override FloatFormatHandling FloatFormatHandling + { + get { return _serializer.FloatFormatHandling; } + set { _serializer.FloatFormatHandling = value; } + } + + public override StringEscapeHandling StringEscapeHandling + { + get { return _serializer.StringEscapeHandling; } + set { _serializer.StringEscapeHandling = value; } + } + + public override string DateFormatString + { + get { return _serializer.DateFormatString; } + set { _serializer.DateFormatString = value; } + } + public override CultureInfo Culture { get { return _serializer.Culture; }