From 3d43fc9c4f7b4ccba48718e03be831becff1a7a6 Mon Sep 17 00:00:00 2001 From: JamesNK Date: Tue, 24 Jan 2012 09:12:32 +0000 Subject: [PATCH] -Increment version to 4.0.7 -Fixed circular reference error when serializing nullable structs -Fixed JsonReader.ReadAsXXX methods not converting string values --- Build/Newtonsoft.Json.nuspec | 2 +- Build/build.ps1 | 4 +- .../JsonTextReaderTest.cs | 136 +++++++--- .../Linq/JTokenReaderTest.cs | 244 ++++++++++++++++++ .../Properties/AssemblyInfo.cs | 4 +- .../Serialization/JsonSerializerTest.cs | 109 ++++++-- Src/Newtonsoft.Json/Bson/BsonReader.cs | 75 ++++-- Src/Newtonsoft.Json/JsonReader.cs | 14 +- Src/Newtonsoft.Json/JsonTextReader.cs | 49 ++-- Src/Newtonsoft.Json/Linq/JTokenReader.cs | 63 ++++- .../Properties/AssemblyInfo.cs | 4 +- .../Serialization/DefaultContractResolver.cs | 10 +- .../Serialization/JsonContract.cs | 4 +- 13 files changed, 590 insertions(+), 128 deletions(-) diff --git a/Build/Newtonsoft.Json.nuspec b/Build/Newtonsoft.Json.nuspec index 3e83f332..d8b232e3 100644 --- a/Build/Newtonsoft.Json.nuspec +++ b/Build/Newtonsoft.Json.nuspec @@ -3,7 +3,7 @@ Newtonsoft.Json Json.NET - 4.0.6 + 4.0.7 James Newton-King Json.NET is a popular high-performance JSON framework for .NET en-US diff --git a/Build/build.ps1 b/Build/build.ps1 index cbaa0b55..3a9bee0c 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -1,6 +1,6 @@ properties { - $zipFileName = "Json40r6.zip" - $majorVersion = "4.0.6" + $zipFileName = "Json40r7.zip" + $majorVersion = "4.0.7" $version = GetVersion $majorVersion $signAssemblies = $false $signKeyPath = "D:\Development\Releases\newtonsoft.snk" diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs index 6ffcf8a8..446512c6 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs @@ -1302,6 +1302,23 @@ bye", reader.Value); Assert.AreEqual(JsonToken.EndObject, reader.TokenType); } + [Test] + [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Could not convert string to DateTimeOffset: blablahbla. Line 1, position 22.")] + public void ReadAsDateTimeOffsetBadString() + { + string json = @"{""Offset"":""blablahbla""}"; + + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + + reader.ReadAsDateTimeOffset(); + } + [Test] public void ReadAsDateTimeOffsetHoursOnly() { @@ -1346,46 +1363,6 @@ bye", reader.Value); Assert.AreEqual(JsonToken.EndObject, reader.TokenType); } - [Test] - [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error parsing null value. Line 0, position 0.")] - public void MatchWithInsufficentCharacters() - { - JsonTextReader reader = new JsonTextReader(new StringReader(@"nul")); - reader.Read(); - } - - [Test] - [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error parsing null value. Line 0, position 0.")] - public void MatchWithWrongCharacters() - { - JsonTextReader reader = new JsonTextReader(new StringReader(@"nulz")); - reader.Read(); - } - - [Test] - [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error parsing null value. Line 1, position 4.")] - public void MatchWithNoTrailingSeperator() - { - JsonTextReader reader = new JsonTextReader(new StringReader(@"nullz")); - reader.Read(); - } - - [Test] - [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Unexpected end while parsing comment. Line 1, position 6.")] - public void UnclosedComment() - { - JsonTextReader reader = new JsonTextReader(new StringReader(@"/* sdf")); - reader.Read(); - } - - [Test] - [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error parsing comment. Expected: *, got s. Line 1, position 1.")] - public void BadCommentStart() - { - JsonTextReader reader = new JsonTextReader(new StringReader(@"/sdf")); - reader.Read(); - } - [Test] public void ReadAsDateTimeOffsetIsoDate() { @@ -1459,6 +1436,85 @@ bye", reader.Value); } #endif + [Test] + public void ReadAsDecimalInt() + { + string json = @"{""Name"":1}"; + + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + + reader.ReadAsDecimal(); + Assert.AreEqual(JsonToken.Float, reader.TokenType); + Assert.AreEqual(typeof(decimal), reader.ValueType); + Assert.AreEqual(1, reader.Value); + } + + [Test] + [ExpectedException(typeof(FormatException), ExpectedMessage = "Input string was not in a correct format.")] + public void ReadAsIntDecimal() + { + string json = @"{""Name"": 1.1}"; + + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + + reader.ReadAsInt32(); + Assert.AreEqual(JsonToken.Integer, reader.TokenType); + Assert.AreEqual(typeof(int), reader.ValueType); + Assert.AreEqual(1, reader.Value); + } + + [Test] + [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error parsing null value. Line 0, position 0.")] + public void MatchWithInsufficentCharacters() + { + JsonTextReader reader = new JsonTextReader(new StringReader(@"nul")); + reader.Read(); + } + + [Test] + [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error parsing null value. Line 0, position 0.")] + public void MatchWithWrongCharacters() + { + JsonTextReader reader = new JsonTextReader(new StringReader(@"nulz")); + reader.Read(); + } + + [Test] + [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error parsing null value. Line 1, position 4.")] + public void MatchWithNoTrailingSeperator() + { + JsonTextReader reader = new JsonTextReader(new StringReader(@"nullz")); + reader.Read(); + } + + [Test] + [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Unexpected end while parsing comment. Line 1, position 6.")] + public void UnclosedComment() + { + JsonTextReader reader = new JsonTextReader(new StringReader(@"/* sdf")); + reader.Read(); + } + + [Test] + [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error parsing comment. Expected: *, got s. Line 1, position 1.")] + public void BadCommentStart() + { + JsonTextReader reader = new JsonTextReader(new StringReader(@"/sdf")); + reader.Read(); + } + [Test] public void ReadAsDecimal() { diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs index aee77d7b..36e784eb 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs @@ -31,6 +31,7 @@ using Newtonsoft.Json; using System.IO; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Tests.Serialization; +using Newtonsoft.Json.Tests.TestObjects; namespace Newtonsoft.Json.Tests.Linq { @@ -111,6 +112,65 @@ namespace Newtonsoft.Json.Tests.Linq Assert.IsFalse(jsonReader.Read()); } } + + [Test] + [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Could not convert string to DateTimeOffset: blablahbla. Line 1, position 22.")] + public void ReadAsDateTimeOffsetBadString() + { + string json = @"{""Offset"":""blablahbla""}"; + + JObject o = JObject.Parse(json); + + JsonReader reader = o.CreateReader(); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + + reader.ReadAsDateTimeOffset(); + } + + [Test] + [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error reading date. Expected bytes but got Boolean. Line 1, position 14.")] + public void ReadAsDateTimeOffsetBoolean() + { + string json = @"{""Offset"":true}"; + + JObject o = JObject.Parse(json); + + JsonReader reader = o.CreateReader(); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + + reader.ReadAsDateTimeOffset(); + } + + [Test] + public void ReadAsDateTimeOffsetString() + { + string json = @"{""Offset"":""2012-01-24T03:50Z""}"; + + JObject o = JObject.Parse(json); + + JsonReader reader = o.CreateReader(); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + + reader.ReadAsDateTimeOffset(); + Assert.AreEqual(JsonToken.Date, reader.TokenType); + Assert.AreEqual(typeof (DateTimeOffset), reader.ValueType); + Assert.AreEqual(new DateTimeOffset(2012, 1, 24, 3, 50, 0, TimeSpan.Zero), reader.Value); + } #endif [Test] @@ -331,5 +391,189 @@ namespace Newtonsoft.Json.Tests.Linq Assert.AreEqual(new byte[] { 72, 63, 62, 71, 92, 55 }, newObject.Data); } } + + [Test] + public void DeserializeStringInt() + { + string json = @"{ + ""PreProperty"": ""99"", + ""PostProperty"": ""-1"" +}"; + + JObject o = JObject.Parse(json); + + JsonSerializer serializer = new JsonSerializer(); + + using (JsonReader nodeReader = o.CreateReader()) + { + MyClass c = serializer.Deserialize(nodeReader); + + Assert.AreEqual(99, c.PreProperty); + Assert.AreEqual(-1, c.PostProperty); + } + } + + [Test] + public void ReadAsDecimalInt() + { + string json = @"{""Name"":1}"; + + JObject o = JObject.Parse(json); + + JsonReader reader = o.CreateReader(); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + + reader.ReadAsDecimal(); + Assert.AreEqual(JsonToken.Float, reader.TokenType); + Assert.AreEqual(typeof(decimal), reader.ValueType); + Assert.AreEqual(1, reader.Value); + } + + [Test] + public void ReadAsInt32Int() + { + string json = @"{""Name"":1}"; + + JObject o = JObject.Parse(json); + + JsonReader reader = o.CreateReader(); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + + reader.ReadAsInt32(); + Assert.AreEqual(JsonToken.Integer, reader.TokenType); + Assert.AreEqual(typeof(int), reader.ValueType); + Assert.AreEqual(1, reader.Value); + } + + [Test] + [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Could not convert string to integer: hi. Line 1, position 12.")] + public void ReadAsInt32BadString() + { + string json = @"{""Name"":""hi""}"; + + JObject o = JObject.Parse(json); + + JsonReader reader = o.CreateReader(); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + + reader.ReadAsInt32(); + Assert.AreEqual(JsonToken.Integer, reader.TokenType); + Assert.AreEqual(typeof(int), reader.ValueType); + Assert.AreEqual(1, reader.Value); + } + + [Test] + [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error reading integer. Expected a number but got Boolean. Line 1, position 12.")] + public void ReadAsInt32Boolean() + { + string json = @"{""Name"":true}"; + + JObject o = JObject.Parse(json); + + JsonReader reader = o.CreateReader(); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + + reader.ReadAsInt32(); + } + + [Test] + public void ReadAsDecimalString() + { + string json = @"{""Name"":""1.1""}"; + + JObject o = JObject.Parse(json); + + JsonReader reader = o.CreateReader(); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + + reader.ReadAsDecimal(); + Assert.AreEqual(JsonToken.Float, reader.TokenType); + Assert.AreEqual(typeof(decimal), reader.ValueType); + Assert.AreEqual(1.1m, reader.Value); + } + + [Test] + [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Could not convert string to decimal: blah. Line 1, position 14.")] + public void ReadAsDecimalBadString() + { + string json = @"{""Name"":""blah""}"; + + JObject o = JObject.Parse(json); + + JsonReader reader = o.CreateReader(); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + + reader.ReadAsDecimal(); + } + + [Test] + [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Error reading decimal. Expected a number but got Boolean. Line 1, position 12.")] + public void ReadAsDecimalBoolean() + { + string json = @"{""Name"":true}"; + + JObject o = JObject.Parse(json); + + JsonReader reader = o.CreateReader(); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + + reader.ReadAsDecimal(); + } + + [Test] + public void ReadAsDecimalNull() + { + string json = @"{""Name"":null}"; + + JObject o = JObject.Parse(json); + + JsonReader reader = o.CreateReader(); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.StartObject, reader.TokenType); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); + + reader.ReadAsDecimal(); + Assert.AreEqual(JsonToken.Null, reader.TokenType); + Assert.AreEqual(null, reader.ValueType); + Assert.AreEqual(null, reader.Value); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs index 7923661d..d3b781d0 100644 --- a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs +++ b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs @@ -64,7 +64,7 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("4.0.5.0")] +[assembly: AssemblyVersion("4.0.7.0")] #if !PocketPC -[assembly: AssemblyFileVersion("4.0.5.14519")] +[assembly: AssemblyFileVersion("4.0.7.14524")] #endif diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index c19ec2bc..3a8de615 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -1044,7 +1044,7 @@ keyword such as type of business."" } [Test] - [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Required property 'FirstName' expects a value but got null. Line 6, position 2.")] + [ExpectedException(typeof (JsonSerializationException), ExpectedMessage = "Required property 'FirstName' expects a value but got null. Line 6, position 2.")] public void DeserializeRequiredMembersClassNullRequiredValueProperty() { string json = @"{ @@ -1074,7 +1074,7 @@ keyword such as type of business."" } [Test] - [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Required property 'LastName' not found in JSON. Line 3, position 2.")] + [ExpectedException(typeof (JsonSerializationException), ExpectedMessage = "Required property 'LastName' not found in JSON. Line 3, position 2.")] public void RequiredMembersClassMissingRequiredProperty() { string json = @"{ @@ -1160,7 +1160,7 @@ keyword such as type of business."" } [Test] - [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Could not create an instance of type Newtonsoft.Json.Tests.TestObjects.ICo. Type is an interface or abstract class and cannot be instantated. Line 1, position 14.")] + [ExpectedException(typeof (JsonSerializationException), ExpectedMessage = @"Could not create an instance of type Newtonsoft.Json.Tests.TestObjects.ICo. Type is an interface or abstract class and cannot be instantated. Line 1, position 14.")] public void DeserializeInterfaceProperty() { InterfacePropertyTestClass testClass = new InterfacePropertyTestClass(); @@ -1832,7 +1832,7 @@ keyword such as type of business."" #endif [Test] - [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Unable to find a constructor to use for type Newtonsoft.Json.Tests.TestObjects.Event. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Line 1, position 15.")] + [ExpectedException(typeof (JsonSerializationException), ExpectedMessage = @"Unable to find a constructor to use for type Newtonsoft.Json.Tests.TestObjects.Event. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Line 1, position 15.")] public void FailWhenClassWithNoDefaultConstructorHasMultipleConstructorsWithArguments() { string json = @"{""sublocation"":""AlertEmailSender.Program.Main"",""userId"":0,""type"":0,""summary"":""Loading settings variables"",""details"":null,""stackTrace"":"" at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)\r\n at System.Environment.get_StackTrace()\r\n at mr.Logging.Event..ctor(String summary) in C:\\Projects\\MRUtils\\Logging\\Event.vb:line 71\r\n at AlertEmailSender.Program.Main(String[] args) in C:\\Projects\\AlertEmailSender\\AlertEmailSender\\Program.cs:line 25"",""tag"":null,""time"":""\/Date(1249591032026-0400)\/""}"; @@ -1872,7 +1872,7 @@ keyword such as type of business."" } [Test] - [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Cannot deserialize JSON array into type 'Newtonsoft.Json.Tests.TestObjects.Person'. Line 1, position 1.")] + [ExpectedException(typeof (JsonSerializationException), ExpectedMessage = @"Cannot deserialize JSON array into type 'Newtonsoft.Json.Tests.TestObjects.Person'. Line 1, position 1.")] public void CannotDeserializeArrayIntoObject() { string json = @"[]"; @@ -1881,7 +1881,7 @@ keyword such as type of business."" } [Test] - [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Cannot deserialize JSON object into type 'System.Collections.Generic.List`1[Newtonsoft.Json.Tests.TestObjects.Person]'. Line 1, position 2.")] + [ExpectedException(typeof (JsonSerializationException), ExpectedMessage = @"Cannot deserialize JSON object into type 'System.Collections.Generic.List`1[Newtonsoft.Json.Tests.TestObjects.Person]'. Line 1, position 2.")] public void CannotDeserializeObjectIntoArray() { string json = @"{}"; @@ -1890,7 +1890,7 @@ keyword such as type of business."" } [Test] - [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Cannot populate JSON array onto type 'Newtonsoft.Json.Tests.TestObjects.Person'. Line 1, position 1.")] + [ExpectedException(typeof (JsonSerializationException), ExpectedMessage = @"Cannot populate JSON array onto type 'Newtonsoft.Json.Tests.TestObjects.Person'. Line 1, position 1.")] public void CannotPopulateArrayIntoObject() { string json = @"[]"; @@ -1899,7 +1899,7 @@ keyword such as type of business."" } [Test] - [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Cannot populate JSON object onto type 'System.Collections.Generic.List`1[Newtonsoft.Json.Tests.TestObjects.Person]'. Line 1, position 2.")] + [ExpectedException(typeof (JsonSerializationException), ExpectedMessage = @"Cannot populate JSON object onto type 'System.Collections.Generic.List`1[Newtonsoft.Json.Tests.TestObjects.Person]'. Line 1, position 2.")] public void CannotPopulateObjectIntoArray() { string json = @"{}"; @@ -1931,14 +1931,14 @@ keyword such as type of business."" } [Test] - [ExpectedException(typeof(JsonReaderException), ExpectedMessage = @"Could not convert string to integer: . Line 1, position 15.")] + [ExpectedException(typeof (JsonReaderException), ExpectedMessage = @"Could not convert string to integer: . Line 1, position 15.")] public void DeserializeEnsureTypeEmptyStringToIntError() { JsonConvert.DeserializeObject("{ReadTimeout:''}"); } [Test] - [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = @"Error converting value {null} to type 'System.Int32'. Line 1, position 17.")] + [ExpectedException(typeof (JsonSerializationException), ExpectedMessage = @"Error converting value {null} to type 'System.Int32'. Line 1, position 17.")] public void DeserializeEnsureTypeNullToIntError() { JsonConvert.DeserializeObject("{ReadTimeout:null}"); @@ -2053,7 +2053,7 @@ keyword such as type of business."" } [Test] - [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Could not convert string 'Newtonsoft.Json.Tests.TestObjects.Person' to dictionary key type 'Newtonsoft.Json.Tests.TestObjects.Person'. Create a TypeConverter to convert from the string to the key type object. Line 2, position 46.")] + [ExpectedException(typeof (JsonSerializationException), ExpectedMessage = "Could not convert string 'Newtonsoft.Json.Tests.TestObjects.Person' to dictionary key type 'Newtonsoft.Json.Tests.TestObjects.Person'. Create a TypeConverter to convert from the string to the key type object. Line 2, position 46.")] public void DeserializePersonKeyedDictionary() { string json = @@ -2318,7 +2318,7 @@ keyword such as type of business."" } [Test] - [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Unable to find a default constructor to use for type Newtonsoft.Json.Tests.Serialization.JsonSerializerTest+DictionaryWithNoDefaultConstructor. Line 1, position 6.")] + [ExpectedException(typeof (JsonSerializationException), ExpectedMessage = "Unable to find a default constructor to use for type Newtonsoft.Json.Tests.Serialization.JsonSerializerTest+DictionaryWithNoDefaultConstructor. Line 1, position 6.")] public void DeserializeDictionaryWithNoDefaultConstructor() { string json = "{key1:'value',key2:'value',key3:'value'}"; @@ -3267,7 +3267,7 @@ keyword such as type of business."" } [Test] - [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Additional content found in JSON reference object. A JSON reference object should only have a $ref property. Line 6, position 11.")] + [ExpectedException(typeof (JsonSerializationException), ExpectedMessage = "Additional content found in JSON reference object. A JSON reference object should only have a $ref property. Line 6, position 11.")] public void SerializeRefAdditionalContent() { //Additional text found in JSON string after finishing deserializing object. @@ -3286,7 +3286,7 @@ keyword such as type of business."" } [Test] - [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "JSON reference $ref property must have a string or null value. Line 5, position 14.")] + [ExpectedException(typeof (JsonSerializationException), ExpectedMessage = "JSON reference $ref property must have a string or null value. Line 5, position 14.")] public void SerializeRefBadType() { //Additional text found in JSON string after finishing deserializing object. @@ -4280,7 +4280,7 @@ keyword such as type of business."" } [Test] - [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Error converting value {null} to type 'System.DateTime'. Line 1, position 4.")] + [ExpectedException(typeof (JsonSerializationException), ExpectedMessage = "Error converting value {null} to type 'System.DateTime'. Line 1, position 4.")] public void DeserializeNullDateTimeValueTest() { JsonConvert.DeserializeObject("null", typeof (DateTime)); @@ -5020,7 +5020,7 @@ keyword such as type of business."" [Test] public void DeserializeByteArrayWithTypeNameHandling() { - TestObject test = new TestObject("Test", new byte[] { 72, 63, 62, 71, 92, 55 }); + TestObject test = new TestObject("Test", new byte[] {72, 63, 62, 71, 92, 55}); JsonSerializer serializer = new JsonSerializer(); serializer.TypeNameHandling = TypeNameHandling.All; @@ -5042,7 +5042,7 @@ keyword such as type of business."" TestObject newObject = (TestObject) serializer.Deserialize(bsonReader); Assert.AreEqual("Test", newObject.Name); - Assert.AreEqual(new byte[] { 72, 63, 62, 71, 92, 55 }, newObject.Data); + Assert.AreEqual(new byte[] {72, 63, 62, 71, 92, 55}, newObject.Data); } } @@ -5066,7 +5066,7 @@ keyword such as type of business."" Assert.AreEqual(1.5m, c.Quantity); Assert.AreEqual(2.2d, c.OptionalQuantity); } - finally + finally { Thread.CurrentThread.CurrentCulture = initialCulture; Thread.CurrentThread.CurrentUICulture = initialCulture; @@ -5077,7 +5077,7 @@ keyword such as type of business."" [Test] public void ReadForTypeHackFixDecimal() { - IList d1 = new List { 1.1m}; + IList d1 = new List {1.1m}; string json = JsonConvert.SerializeObject(d1); @@ -5090,7 +5090,7 @@ keyword such as type of business."" [Test] public void ReadForTypeHackFixDateTimeOffset() { - IList d1 = new List { null }; + IList d1 = new List {null}; string json = JsonConvert.SerializeObject(d1); @@ -5103,7 +5103,7 @@ keyword such as type of business."" [Test] public void ReadForTypeHackFixByteArray() { - IList d1 = new List { null }; + IList d1 = new List {null}; string json = JsonConvert.SerializeObject(d1); @@ -5131,7 +5131,7 @@ keyword such as type of business."" } [Test] - [ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Error converting value {null} to type 'System.Int32'. Line 5, position 7.")] + [ExpectedException(typeof (JsonSerializationException), ExpectedMessage = "Error converting value {null} to type 'System.Int32'. Line 5, position 7.")] public void DeserializeNullInt() { string json = @"[ @@ -5144,6 +5144,60 @@ keyword such as type of business."" List numbers = JsonConvert.DeserializeObject>(json); // JsonSerializationException : Error converting value {null} to type 'System.Int32'. Line 5, position 7. } + + [Test] + public void SerializeNullableWidgetStruct() + { + Widget widget = new Widget {Id = new WidgetId {Value = "id"}}; + + string json = JsonConvert.SerializeObject(widget); + + Assert.AreEqual(@"{""Id"":{""Value"":""id""}}", json); + } + + [Test] + public void DeserializeNullableWidgetStruct() + { + string json = @"{""Id"":{""Value"":""id""}}"; + + Widget w = JsonConvert.DeserializeObject(json); + + Assert.AreEqual(new WidgetId { Value = "id" }, w.Id); + Assert.AreEqual(new WidgetId { Value = "id" }, w.Id.Value); + Assert.AreEqual("id", w.Id.Value.Value); + } + + [Test] + [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Unexpected token when reading integer: Boolean. Line 2, position 22.")] + public void DeserializeBoolInt() + { + string json = @"{ + ""PreProperty"": true, + ""PostProperty"": ""-1"" +}"; + + JsonConvert.DeserializeObject(json); + } + + [Test] + [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Unexpected end when reading integer. Line 2, position 18.")] + public void DeserializeUnexpectedEndInt() + { + string json = @"{ + ""PreProperty"": "; + + JsonConvert.DeserializeObject(json); + } + } + + public class Widget + { + public WidgetId? Id { get; set; } + } + + public struct WidgetId + { + public string Value { get; set; } } public class DecimalTestClass @@ -5156,7 +5210,7 @@ keyword such as type of business."" { public TestObject() { - + } public TestObject(string name, byte[] data) @@ -5178,12 +5232,12 @@ keyword such as type of business."" public Uri Uri { get; set; } } - class Aa + internal class Aa { public int no; } - class Bb : Aa + internal class Bb : Aa { public bool no; } @@ -5198,8 +5252,7 @@ keyword such as type of business."" [JsonProperty] public string Name { get; set; } - [JsonProperty] - public ConcurrentDictionary Components; + [JsonProperty] public ConcurrentDictionary Components; public GameObject() { @@ -5212,7 +5265,7 @@ keyword such as type of business."" public class Component { [JsonIgnore] // Ignore circular reference - public GameObject GameObject { get; set; } + public GameObject GameObject { get; set; } public Component() { diff --git a/Src/Newtonsoft.Json/Bson/BsonReader.cs b/Src/Newtonsoft.Json/Bson/BsonReader.cs index 0d178852..470d1331 100644 --- a/Src/Newtonsoft.Json/Bson/BsonReader.cs +++ b/Src/Newtonsoft.Json/Bson/BsonReader.cs @@ -198,7 +198,7 @@ namespace Newtonsoft.Json.Bson if (ReaderIsSerializerInArray()) return null; - throw new JsonReaderException("Error reading bytes. Expected bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); + throw CreateReaderException(this, "Error reading bytes. Expected bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); } private bool IsWrappedInTypeObject() @@ -219,7 +219,7 @@ namespace Newtonsoft.Json.Bson } } - throw new JsonReaderException("Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject)); + throw CreateReaderException(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject)); } return false; @@ -233,18 +233,33 @@ namespace Newtonsoft.Json.Bson { Read(); - if (TokenType == JsonToken.Null) - return null; if (TokenType == JsonToken.Integer || TokenType == JsonToken.Float) { SetToken(JsonToken.Float, Convert.ToDecimal(Value, CultureInfo.InvariantCulture)); return (decimal)Value; } + if (TokenType == JsonToken.Null) + return null; + + decimal d; + if (TokenType == JsonToken.String) + { + if (decimal.TryParse((string)Value, NumberStyles.Number, Culture, out d)) + { + SetToken(JsonToken.Float, d); + return d; + } + else + { + throw CreateReaderException(this, "Could not convert string to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, Value)); + } + } + if (ReaderIsSerializerInArray()) return null; - throw new JsonReaderException("Error reading decimal. Expected a number but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); + throw CreateReaderException(this, "Error reading decimal. Expected a number but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); } /// @@ -260,13 +275,28 @@ namespace Newtonsoft.Json.Bson SetToken(JsonToken.Float, Convert.ToInt32(Value, CultureInfo.InvariantCulture)); return (int)Value; } + if (TokenType == JsonToken.Null) return null; + int i; + if (TokenType == JsonToken.String) + { + if (int.TryParse((string)Value, NumberStyles.Integer, Culture, out i)) + { + SetToken(JsonToken.Integer, i); + return i; + } + else + { + throw CreateReaderException(this, "Could not convert string to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, Value)); + } + } + if (ReaderIsSerializerInArray()) return null; - throw new JsonReaderException("Error reading integer. Expected a number but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); + throw CreateReaderException(this, "Error reading integer. Expected a number but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); } #if !NET20 @@ -280,18 +310,33 @@ namespace Newtonsoft.Json.Bson { Read(); - if (TokenType == JsonToken.Null) - return null; if (TokenType == JsonToken.Date) { SetToken(JsonToken.Date, new DateTimeOffset((DateTime) Value)); return (DateTimeOffset) Value; } + if (TokenType == JsonToken.Null) + return null; + + DateTimeOffset dt; + if (TokenType == JsonToken.String) + { + if (DateTimeOffset.TryParse((string)Value, Culture, DateTimeStyles.None, out dt)) + { + SetToken(JsonToken.Date, dt); + return dt; + } + else + { + throw CreateReaderException(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, Value)); + } + } + if (ReaderIsSerializerInArray()) return null; - throw new JsonReaderException("Error reading date. Expected bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); + throw CreateReaderException(this, "Error reading date. Expected bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); } #endif @@ -320,7 +365,7 @@ namespace Newtonsoft.Json.Bson case BsonReaderState.CodeWScopeScopeEnd: return ReadCodeWScope(); default: - throw new JsonReaderException("Unexpected state: {0}".FormatWith(CultureInfo.InvariantCulture, _bsonReaderState)); + throw CreateReaderException(this, "Unexpected state: {0}".FormatWith(CultureInfo.InvariantCulture, _bsonReaderState)); } } catch (EndOfStreamException) @@ -411,7 +456,7 @@ namespace Newtonsoft.Json.Bson } else { - throw new JsonReaderException("Unexpected state when reading BSON reference: " + _bsonReaderState); + throw CreateReaderException(this, "Unexpected state when reading BSON reference: " + _bsonReaderState); } } case State.PostValue: @@ -430,11 +475,11 @@ namespace Newtonsoft.Json.Bson } else { - throw new JsonReaderException("Unexpected state when reading BSON reference: " + _bsonReaderState); + throw CreateReaderException(this, "Unexpected state when reading BSON reference: " + _bsonReaderState); } } default: - throw new JsonReaderException("Unexpected state when reading BSON reference: " + CurrentState); + throw CreateReaderException(this, "Unexpected state when reading BSON reference: " + CurrentState); } } @@ -487,7 +532,7 @@ namespace Newtonsoft.Json.Bson else if (context.Position == lengthMinusEnd) { if (ReadByte() != 0) - throw new JsonReaderException("Unexpected end of object byte value."); + throw CreateReaderException(this, "Unexpected end of object byte value."); PopContext(); if (_currentContext != null) @@ -499,7 +544,7 @@ namespace Newtonsoft.Json.Bson } else { - throw new JsonReaderException("Read past end of current container context."); + throw CreateReaderException(this, "Read past end of current container context."); } case State.ConstructorStart: break; diff --git a/Src/Newtonsoft.Json/JsonReader.cs b/Src/Newtonsoft.Json/JsonReader.cs index b22fba32..8478c8c9 100644 --- a/Src/Newtonsoft.Json/JsonReader.cs +++ b/Src/Newtonsoft.Json/JsonReader.cs @@ -103,6 +103,7 @@ namespace Newtonsoft.Json internal State _currentState; private JTokenType _currentTypeContext; private bool _serializerInArray; + private CultureInfo _culture; internal void SetSerializeInArray(bool serializerInArray) { @@ -181,6 +182,15 @@ namespace Newtonsoft.Json } } + /// + /// Gets or sets the culture used when reading JSON. Defaults to . + /// + public CultureInfo Culture + { + get { return _culture ?? CultureInfo.InvariantCulture; } + set { _culture = value; } + } + /// /// Initializes a new instance of the class with the specified . /// @@ -473,7 +483,7 @@ namespace Newtonsoft.Json int lineNumber; int linePosition; - if (lineInfo != null) + if (lineInfo != null && lineInfo.HasLineInfo()) { lineNumber = lineInfo.LineNumber; linePosition = lineInfo.LinePosition; @@ -492,7 +502,7 @@ namespace Newtonsoft.Json if (!message.EndsWith(".")) message += "."; - if (lineInfo != null) + if (lineInfo != null && lineInfo.HasLineInfo()) message += " Line {0}, position {1}.".FormatWith(CultureInfo.InvariantCulture, lineInfo.LineNumber, lineInfo.LinePosition); return message; diff --git a/Src/Newtonsoft.Json/JsonTextReader.cs b/Src/Newtonsoft.Json/JsonTextReader.cs index 65987770..3da8fb13 100644 --- a/Src/Newtonsoft.Json/JsonTextReader.cs +++ b/Src/Newtonsoft.Json/JsonTextReader.cs @@ -51,7 +51,6 @@ namespace Newtonsoft.Json } private ReadType _readType; - private CultureInfo _culture; private readonly TextReader _reader; @@ -64,15 +63,6 @@ namespace Newtonsoft.Json private StringBuffer _buffer; private StringReference _stringReference; - /// - /// Gets or sets the culture used when reading JSON. Defaults to . - /// - public CultureInfo Culture - { - get { return _culture ?? CultureInfo.InvariantCulture; } - set { _culture = value; } - } - /// /// Initializes a new instance of the class with the specified . /// @@ -394,8 +384,10 @@ namespace Newtonsoft.Json if (TokenType == JsonToken.Null) return null; + if (TokenType == JsonToken.Bytes) return (byte[])Value; + if (TokenType == JsonToken.StartArray) { List data = new List(); @@ -442,16 +434,24 @@ namespace Newtonsoft.Json throw CreateReaderException(this, "Unexpected end when reading decimal."); } while (TokenType == JsonToken.Comment); - if (TokenType == JsonToken.Null) - return null; if (TokenType == JsonToken.Float) return (decimal?)Value; + if (TokenType == JsonToken.Null) + return null; + decimal d; - if (TokenType == JsonToken.String && decimal.TryParse((string)Value, NumberStyles.Number, Culture, out d)) + if (TokenType == JsonToken.String) { - SetToken(JsonToken.Float, d); - return d; + if (decimal.TryParse((string)Value, NumberStyles.Number, Culture, out d)) + { + SetToken(JsonToken.Float, d); + return d; + } + else + { + throw CreateReaderException(this, "Could not convert string to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, Value)); + } } if (ReaderIsSerializerInArray()) @@ -476,6 +476,7 @@ namespace Newtonsoft.Json if (TokenType == JsonToken.Integer) return (int?)Value; + if (TokenType == JsonToken.Null) return null; @@ -514,16 +515,24 @@ namespace Newtonsoft.Json throw CreateReaderException(this, "Unexpected end when reading date."); } while (TokenType == JsonToken.Comment); - if (TokenType == JsonToken.Null) - return null; if (TokenType == JsonToken.Date) return (DateTimeOffset)Value; + if (TokenType == JsonToken.Null) + return null; + DateTimeOffset dt; - if (TokenType == JsonToken.String && DateTimeOffset.TryParse((string)Value, Culture, DateTimeStyles.None, out dt)) + if (TokenType == JsonToken.String) { - SetToken(JsonToken.Date, dt); - return dt; + if (DateTimeOffset.TryParse((string)Value, Culture, DateTimeStyles.None, out dt)) + { + SetToken(JsonToken.Date, dt); + return dt; + } + else + { + throw CreateReaderException(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, Value)); + } } if (ReaderIsSerializerInArray()) diff --git a/Src/Newtonsoft.Json/Linq/JTokenReader.cs b/Src/Newtonsoft.Json/Linq/JTokenReader.cs index e52fc75b..34f84c07 100644 --- a/Src/Newtonsoft.Json/Linq/JTokenReader.cs +++ b/Src/Newtonsoft.Json/Linq/JTokenReader.cs @@ -62,7 +62,7 @@ namespace Newtonsoft.Json.Linq if (ReaderIsSerializerInArray()) return null; - throw new JsonReaderException("Error reading bytes. Expected bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); + throw CreateReaderException(this, "Error reading bytes. Expected bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); } private bool IsWrappedInTypeObject() @@ -83,7 +83,7 @@ namespace Newtonsoft.Json.Linq } } - throw new JsonReaderException("Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject)); + throw CreateReaderException(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject)); } return false; @@ -97,18 +97,33 @@ namespace Newtonsoft.Json.Linq { Read(); - if (TokenType == JsonToken.Null) - return null; if (TokenType == JsonToken.Integer || TokenType == JsonToken.Float) { SetToken(JsonToken.Float, Convert.ToDecimal(Value, CultureInfo.InvariantCulture)); return (decimal) Value; } + if (TokenType == JsonToken.Null) + return null; + + decimal d; + if (TokenType == JsonToken.String) + { + if (decimal.TryParse((string)Value, NumberStyles.Number, Culture, out d)) + { + SetToken(JsonToken.Float, d); + return d; + } + else + { + throw CreateReaderException(this, "Could not convert string to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, Value)); + } + } + if (ReaderIsSerializerInArray()) return null; - throw new JsonReaderException("Error reading decimal. Expected a number but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); + throw CreateReaderException(this, "Error reading decimal. Expected a number but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); } /// @@ -124,13 +139,28 @@ namespace Newtonsoft.Json.Linq SetToken(JsonToken.Integer, Convert.ToInt32(Value, CultureInfo.InvariantCulture)); return (int)Value; } + if (TokenType == JsonToken.Null) return null; + int i; + if (TokenType == JsonToken.String) + { + if (int.TryParse((string)Value, NumberStyles.Integer, Culture, out i)) + { + SetToken(JsonToken.Integer, i); + return i; + } + else + { + throw CreateReaderException(this, "Could not convert string to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, Value)); + } + } + if (ReaderIsSerializerInArray()) return null; - throw new JsonReaderException("Error reading integer. Expected a number but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); + throw CreateReaderException(this, "Error reading integer. Expected a number but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); } #if !NET20 @@ -142,18 +172,33 @@ namespace Newtonsoft.Json.Linq { Read(); - if (TokenType == JsonToken.Null) - return null; if (TokenType == JsonToken.Date) { SetToken(JsonToken.Date, new DateTimeOffset((DateTime)Value)); return (DateTimeOffset)Value; } + if (TokenType == JsonToken.Null) + return null; + + DateTimeOffset dt; + if (TokenType == JsonToken.String) + { + if (DateTimeOffset.TryParse((string)Value, Culture, DateTimeStyles.None, out dt)) + { + SetToken(JsonToken.Date, dt); + return dt; + } + else + { + throw CreateReaderException(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, Value)); + } + } + if (ReaderIsSerializerInArray()) return null; - throw new JsonReaderException("Error reading date. Expected bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); + throw CreateReaderException(this, "Error reading date. Expected bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); } #endif diff --git a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs index f65a5c9a..3f34b106 100644 --- a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs +++ b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs @@ -83,9 +83,9 @@ using System.Security; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("4.0.5.0")] +[assembly: AssemblyVersion("4.0.7.0")] #if !PocketPC -[assembly: AssemblyFileVersion("4.0.5.14519")] +[assembly: AssemblyFileVersion("4.0.7.14524")] #endif [assembly: CLSCompliant(true)] diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs index 6e2a474d..7b7f9842 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs @@ -285,13 +285,13 @@ namespace Newtonsoft.Json.Serialization JsonObjectContract contract = new JsonObjectContract(objectType); InitializeContract(contract); - contract.MemberSerialization = JsonTypeReflector.GetObjectMemberSerialization(objectType); - contract.Properties.AddRange(CreateProperties(contract.UnderlyingType, contract.MemberSerialization)); + contract.MemberSerialization = JsonTypeReflector.GetObjectMemberSerialization(contract.NonNullableUnderlyingType); + contract.Properties.AddRange(CreateProperties(contract.NonNullableUnderlyingType, contract.MemberSerialization)); // check if a JsonConstructorAttribute has been defined and use that - if (objectType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Any(c => c.IsDefined(typeof(JsonConstructorAttribute), true))) + if (contract.NonNullableUnderlyingType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Any(c => c.IsDefined(typeof(JsonConstructorAttribute), true))) { - ConstructorInfo constructor = GetAttributeConstructor(objectType); + ConstructorInfo constructor = GetAttributeConstructor(contract.NonNullableUnderlyingType); if (constructor != null) { contract.OverrideConstructor = constructor; @@ -300,7 +300,7 @@ namespace Newtonsoft.Json.Serialization } else if (contract.DefaultCreator == null || contract.DefaultCreatorNonPublic) { - ConstructorInfo constructor = GetParametrizedConstructor(objectType); + ConstructorInfo constructor = GetParametrizedConstructor(contract.NonNullableUnderlyingType); if (constructor != null) { contract.ParametrizedConstructor = constructor; diff --git a/Src/Newtonsoft.Json/Serialization/JsonContract.cs b/Src/Newtonsoft.Json/Serialization/JsonContract.cs index ef450b62..9dd85325 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonContract.cs @@ -184,12 +184,12 @@ namespace Newtonsoft.Json.Serialization ValidationUtils.ArgumentNotNull(underlyingType, "underlyingType"); UnderlyingType = underlyingType; - CreatedType = underlyingType; IsNullable = ReflectionUtils.IsNullable(underlyingType); - NonNullableUnderlyingType = (IsNullable && ReflectionUtils.IsNullableType(underlyingType)) ? Nullable.GetUnderlyingType(underlyingType) : underlyingType; + CreatedType = NonNullableUnderlyingType; + IsConvertable = typeof(IConvertible).IsAssignableFrom(NonNullableUnderlyingType); if (NonNullableUnderlyingType == typeof(byte[]))