From 382fb8df6220d3fffbb0ee8cf8a44d8765f60283 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Thu, 4 Oct 2012 00:02:26 +1300 Subject: [PATCH] -Fixed empty strings not correctly deserializing as null onto nullable properties --- .../Serialization/JsonSerializerTest.cs | 34 +++++++++++++++++-- Src/Newtonsoft.Json/JsonReader.cs | 27 +++++++++++++-- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index 9aefe97a..811d90da 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -2246,8 +2246,8 @@ Path '', line 1, position 2.", [Test] public void DeserializeEnsureTypeEmptyStringToIntError() { - ExceptionAssert.Throws( - @"Could not convert string to integer: . Path 'ReadTimeout', line 1, position 15.", + ExceptionAssert.Throws( + @"Error converting value {null} to type 'System.Int32'. Path 'ReadTimeout', line 1, position 15.", () => { JsonConvert.DeserializeObject("{ReadTimeout:''}", new JsonSerializerSettings @@ -7179,6 +7179,36 @@ Parameter name: value", Assert.AreEqual("07/19/2012 14:30:00 +09:30", dateTimeOffset.ToString(CultureInfo.InvariantCulture)); } #endif + +#if !NET20 + public class NullableTestClass + { + public bool? MyNullableBool { get; set; } + public int? MyNullableInteger { get; set; } + public DateTime? MyNullableDateTime { get; set; } + public DateTimeOffset? MyNullableDateTimeOffset { get; set; } + public Decimal? MyNullableDecimal { get; set; } + } + + [Test] + public void TestStringToNullableDeserialization() + { + string json = @"{ + ""MyNullableBool"": """", + ""MyNullableInteger"": """", + ""MyNullableDateTime"": """", + ""MyNullableDateTimeOffset"": """", + ""MyNullableDecimal"": """" +}"; + + NullableTestClass c2 = JsonConvert.DeserializeObject(json); + Assert.IsNull(c2.MyNullableBool); + Assert.IsNull(c2.MyNullableInteger); + Assert.IsNull(c2.MyNullableDateTime); + Assert.IsNull(c2.MyNullableDateTimeOffset); + Assert.IsNull(c2.MyNullableDecimal); + } +#endif } #if !(SILVERLIGHT || NETFX_CORE || PORTABLE) diff --git a/Src/Newtonsoft.Json/JsonReader.cs b/Src/Newtonsoft.Json/JsonReader.cs index 1e1fae44..6bfd3964 100644 --- a/Src/Newtonsoft.Json/JsonReader.cs +++ b/Src/Newtonsoft.Json/JsonReader.cs @@ -388,7 +388,14 @@ namespace Newtonsoft.Json DateTimeOffset dt; if (TokenType == JsonToken.String) { - if (DateTimeOffset.TryParse((string)Value, Culture, DateTimeStyles.RoundtripKind, out dt)) + string s = (string)Value; + if (string.IsNullOrEmpty(s)) + { + SetToken(JsonToken.Null); + return null; + } + + if (DateTimeOffset.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt)) { SetToken(JsonToken.Date, dt); return dt; @@ -500,7 +507,14 @@ namespace Newtonsoft.Json decimal d; if (TokenType == JsonToken.String) { - if (decimal.TryParse((string)Value, NumberStyles.Number, Culture, out d)) + string s = (string)Value; + if (string.IsNullOrEmpty(s)) + { + SetToken(JsonToken.Null); + return null; + } + + if (decimal.TryParse(s, NumberStyles.Number, Culture, out d)) { SetToken(JsonToken.Float, d); return d; @@ -544,7 +558,14 @@ namespace Newtonsoft.Json int i; if (TokenType == JsonToken.String) { - if (int.TryParse((string)Value, NumberStyles.Integer, Culture, out i)) + string s = (string)Value; + if (string.IsNullOrEmpty(s)) + { + SetToken(JsonToken.Null); + return null; + } + + if (int.TryParse(s, NumberStyles.Integer, Culture, out i)) { SetToken(JsonToken.Integer, i); return i;