diff --git a/Build/build.ps1 b/Build/build.ps1 index d1da77cb..a07e88f7 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -1,7 +1,7 @@ properties { - $zipFileName = "Json80r1.zip" + $zipFileName = "Json80r2.zip" $majorVersion = "8.0" - $majorWithReleaseVersion = "8.0.1" + $majorWithReleaseVersion = "8.0.2" $nugetPrelease = $null $version = GetVersion $majorWithReleaseVersion $packageId = "Newtonsoft.Json" diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs index 45cab62c..e9c5ec8f 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs @@ -406,7 +406,7 @@ third line", jsonTextReader.Value); Assert.IsTrue(reader.Read()); Assert.AreEqual(JsonToken.PropertyName, reader.TokenType); - ExceptionAssert.Throws(() => { reader.Read(); }, "Unexpected content while parsing JSON. Path 'u', line 1, position 27."); + ExceptionAssert.Throws(() => { reader.Read(); }, "Unexpected content while parsing JSON. Path 'u', line 1, position 29."); } [Test] @@ -2418,7 +2418,7 @@ new Date()")); { JsonTextReader reader = new JsonTextReader(new StringReader(@"nul")); - ExceptionAssert.Throws(() => { reader.Read(); }, "Error parsing null value. Path '', line 0, position 0."); + ExceptionAssert.Throws(() => { reader.Read(); }, "Unexpected end when reading JSON. Path '', line 1, position 3."); } [Test] @@ -2426,7 +2426,7 @@ new Date()")); { JsonTextReader reader = new JsonTextReader(new StringReader(@"nulz")); - ExceptionAssert.Throws(() => { reader.Read(); }, "Error parsing null value. Path '', line 0, position 0."); + ExceptionAssert.Throws(() => { reader.Read(); }, "Error parsing null value. Path '', line 1, position 3."); } [Test] @@ -3469,11 +3469,16 @@ null//comment 'TRUE', 'false', 'FALSE', + // comment! + /* comment! */ '', null ]"; JsonTextReader reader = new JsonTextReader(new StringReader(json)); +#if DEBUG + reader.SetCharBuffer(new char[10]); +#endif Assert.IsTrue(reader.Read()); Assert.AreEqual("", reader.Path); @@ -3523,14 +3528,86 @@ null//comment Assert.AreEqual(null, reader.ReadAsBoolean()); Assert.AreEqual("[14]", reader.Path); - Assert.IsTrue(reader.Read()); + Assert.AreEqual(null, reader.ReadAsBoolean()); + Assert.AreEqual(JsonToken.EndArray, reader.TokenType); Assert.AreEqual("", reader.Path); - Assert.IsFalse(reader.Read()); + Assert.AreEqual(null, reader.ReadAsBoolean()); + Assert.AreEqual(JsonToken.None, reader.TokenType); Assert.AreEqual("", reader.Path); } #endif + [Test] + public void ReadAsString_Null_AdditionalBadData() + { + string json = @"nullllll"; + + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + + ExceptionAssert.Throws(() => { reader.ReadAsString(); }, "Error parsing null value. Path '', line 1, position 4."); + } + + [Test] + public void ReadAsBoolean_AdditionalBadData() + { + string json = @"falseeeee"; + + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + + ExceptionAssert.Throws(() => { reader.ReadAsBoolean(); }, "Unexpected character encountered while parsing value: e. Path '', line 1, position 5."); + } + + [Test] + public void ReadAsString_AdditionalBadData() + { + string json = @"falseeeee"; + + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + + ExceptionAssert.Throws(() => { reader.ReadAsString(); }, "Unexpected character encountered while parsing value: e. Path '', line 1, position 5."); + } + + [Test] + public void ReadAsBoolean_UnexpectedEnd() + { + string json = @"tru"; + + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + + ExceptionAssert.Throws(() => { reader.ReadAsBoolean(); }, "Unexpected end when reading JSON. Path '', line 1, position 3."); + } + + [Test] + public void ReadAsDateTime_Boolean() + { + string json = @"true"; + + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + + ExceptionAssert.Throws(() => { reader.ReadAsDateTime(); }, "Unexpected character encountered while parsing value: t. Path '', line 1, position 1."); + } + + [Test] + public void ReadAsString_UnexpectedEnd() + { + string json = @"tru"; + + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + + ExceptionAssert.Throws(() => { reader.ReadAsString(); }, "Unexpected end when reading JSON. Path '', line 1, position 3."); + } + + [Test] + public void ReadAsString_Null_UnexpectedEnd() + { + string json = @"nul"; + + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + + ExceptionAssert.Throws(() => { reader.ReadAsString(); }, "Unexpected end when reading JSON. Path '', line 1, position 3."); + } + [Test] public void ReadAsBytes() { diff --git a/Src/Newtonsoft.Json.Tests/Serialization/MetadataPropertyHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/MetadataPropertyHandlingTests.cs index 2353fbd1..f413e85f 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/MetadataPropertyHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/MetadataPropertyHandlingTests.cs @@ -530,39 +530,40 @@ namespace Newtonsoft.Json.Tests.Serialization Assert.AreEqual("AAECAwQFBgcICQ==", (string)o["$value"]); } - public class ItemWithTypedPayload + public class ItemWithUntypedPayload { - public float Payload { get; set; } + public object Payload { get; set; } } [Test] - public void PrimitiveType_MetadataPropertyIgnore_WithType() + public void PrimitiveType_MetadataPropertyIgnore_WithNoType() { - ItemWithTypedPayload actual = JsonConvert.DeserializeObject(@"{ + ItemWithUntypedPayload actual = JsonConvert.DeserializeObject(@"{ ""Payload"": { ""$type"": ""System.Single, mscorlib"", ""$value"": ""5"" } }", - new JsonSerializerSettings()); + new JsonSerializerSettings + { + TypeNameHandling = TypeNameHandling.Auto + }); Assert.AreEqual(5f, actual.Payload); - ExceptionAssert.Throws(() => - { - JsonConvert.DeserializeObject(@"{ + actual = JsonConvert.DeserializeObject(@"{ ""Payload"": { ""$type"": ""System.Single, mscorlib"", ""$value"": ""5"" } }", - new JsonSerializerSettings - { - MetadataPropertyHandling = MetadataPropertyHandling.Ignore - }); - }, @"Cannot deserialize the current JSON object (e.g. {""name"":""value""}) into type 'System.Single' because the type requires a JSON primitive value (e.g. string, number, boolean, null) to deserialize correctly. -To fix this error either change the JSON to a JSON primitive value (e.g. string, number, boolean, null) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object. -Path 'Payload.$type', line 3, position 12."); + new JsonSerializerSettings + { + TypeNameHandling = TypeNameHandling.Auto, + MetadataPropertyHandling = MetadataPropertyHandling.Ignore + }); + + Assert.IsTrue(actual.Payload is JObject); } [Test] diff --git a/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs index 232f7b17..4490fde4 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs @@ -186,7 +186,7 @@ namespace Newtonsoft.Json.Tests.Serialization public void NestedValueObjects() { StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 10000; i++) + for (int i = 0; i < 3; i++) { sb.Append(@"{""$value"":"); } @@ -196,7 +196,7 @@ namespace Newtonsoft.Json.Tests.Serialization var reader = new JsonTextReader(new StringReader(sb.ToString())); var ser = new JsonSerializer(); ser.MetadataPropertyHandling = MetadataPropertyHandling.Default; - ser.Deserialize(reader); + ser.Deserialize(reader); }, "Unexpected token when deserializing primitive value: StartObject. Path '$value', line 1, position 11."); } diff --git a/Src/Newtonsoft.Json/JsonReader.cs b/Src/Newtonsoft.Json/JsonReader.cs index 8baf9e7d..5a2e1ca7 100644 --- a/Src/Newtonsoft.Json/JsonReader.cs +++ b/Src/Newtonsoft.Json/JsonReader.cs @@ -874,10 +874,15 @@ namespace Newtonsoft.Json { if (!Read()) { - throw JsonReaderException.Create(this, "Unexpected end when reading JSON."); + throw CreateUnexpectedEndException(); } } + internal JsonReaderException CreateUnexpectedEndException() + { + return JsonReaderException.Create(this, "Unexpected end when reading JSON."); + } + internal void ReadIntoWrappedTypeObject() { ReaderReadAndAssert(); diff --git a/Src/Newtonsoft.Json/JsonTextReader.cs b/Src/Newtonsoft.Json/JsonTextReader.cs index c65a3772..dc459396 100644 --- a/Src/Newtonsoft.Json/JsonTextReader.cs +++ b/Src/Newtonsoft.Json/JsonTextReader.cs @@ -740,6 +740,7 @@ namespace Newtonsoft.Json case 'f': bool isTrue = currentChar == 't'; string expected = isTrue ? JsonConvert.True : JsonConvert.False; + if (!MatchValueWithTrailingSeparator(expected)) { throw CreateUnexpectedCharacterException(_chars[_charPos]); @@ -951,7 +952,8 @@ namespace Newtonsoft.Json throw CreateUnexpectedCharacterException(_chars[_charPos - 1]); } - throw JsonReaderException.Create(this, "Unexpected end when reading JSON."); + _charPos = _charsUsed; + throw CreateUnexpectedEndException(); } private void ReadFinished() @@ -1550,7 +1552,7 @@ namespace Newtonsoft.Json } else { - throw JsonReaderException.Create(this, "Unexpected end when reading JSON."); + CreateUnexpectedEndException(); } return true; case 'N': @@ -2118,13 +2120,15 @@ namespace Newtonsoft.Json { if (!EnsureChars(value.Length - 1, true)) { - return false; + _charPos = _charsUsed; + throw CreateUnexpectedEndException(); } for (int i = 0; i < value.Length; i++) { if (_chars[_charPos + i] != value[i]) { + _charPos += i; return false; } } diff --git a/Src/Newtonsoft.Json/Serialization/JsonContract.cs b/Src/Newtonsoft.Json/Serialization/JsonContract.cs index a9f885d1..6d0b2c37 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonContract.cs @@ -321,44 +321,7 @@ namespace Newtonsoft.Json.Serialization IsConvertable = ConvertUtils.IsConvertible(NonNullableUnderlyingType); IsEnum = NonNullableUnderlyingType.IsEnum(); - if (NonNullableUnderlyingType == typeof(byte[])) - { - InternalReadType = ReadType.ReadAsBytes; - } - else if (NonNullableUnderlyingType == typeof(int)) - { - InternalReadType = ReadType.ReadAsInt32; - } - else if (NonNullableUnderlyingType == typeof(decimal)) - { - InternalReadType = ReadType.ReadAsDecimal; - } - else if (NonNullableUnderlyingType == typeof(bool)) - { - InternalReadType = ReadType.ReadAsBoolean; - } - else if (NonNullableUnderlyingType == typeof(string)) - { - InternalReadType = ReadType.ReadAsString; - } - else if (NonNullableUnderlyingType == typeof(DateTime)) - { - InternalReadType = ReadType.ReadAsDateTime; - } -#if !NET20 - else if (NonNullableUnderlyingType == typeof(DateTimeOffset)) - { - InternalReadType = ReadType.ReadAsDateTimeOffset; - } -#endif - else if (NonNullableUnderlyingType == typeof(double)) - { - InternalReadType = ReadType.ReadAsDouble; - } - else - { - InternalReadType = ReadType.Read; - } + InternalReadType = ReadType.Read; } internal void InvokeOnSerializing(object o, StreamingContext context) diff --git a/Src/Newtonsoft.Json/Serialization/JsonPrimitiveContract.cs b/Src/Newtonsoft.Json/Serialization/JsonPrimitiveContract.cs index 6631dd7c..8130868f 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonPrimitiveContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonPrimitiveContract.cs @@ -24,6 +24,7 @@ #endregion using System; +using System.Collections.Generic; using Newtonsoft.Json.Utilities; namespace Newtonsoft.Json.Serialization @@ -46,6 +47,29 @@ namespace Newtonsoft.Json.Serialization TypeCode = ConvertUtils.GetTypeCode(underlyingType); IsReadOnlyOrFixedSize = true; + + ReadType readType; + if (ReadTypeMap.TryGetValue(NonNullableUnderlyingType, out readType)) + { + InternalReadType = readType; + } } + + private static readonly Dictionary ReadTypeMap = new Dictionary + { + [typeof(byte[])] = ReadType.ReadAsBytes, + [typeof(byte)] = ReadType.ReadAsInt32, + [typeof(short)] = ReadType.ReadAsInt32, + [typeof(int)] = ReadType.ReadAsInt32, + [typeof(decimal)] = ReadType.ReadAsDecimal, + [typeof(bool)] = ReadType.ReadAsBoolean, + [typeof(string)] = ReadType.ReadAsString, + [typeof(DateTime)] = ReadType.ReadAsDateTime, +#if !NET20 + [typeof(DateTimeOffset)] = ReadType.ReadAsDateTimeOffset, +#endif + [typeof(float)] = ReadType.ReadAsDouble, + [typeof(double)] = ReadType.ReadAsDouble + }; } } \ No newline at end of file