Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/Newtonsoft.Json.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Newton-King <james@newtonking.com>2012-02-23 14:07:41 +0400
committerJames Newton-King <james@newtonking.com>2012-02-23 14:07:41 +0400
commit0d6ad0b76ed3b97275122a3bda8171b31cac53e8 (patch)
treed2bd78a0ff008408269831f71c2d104f7685a9c7
parent4f8832adc084c83f3825f640afee8b30246eace8 (diff)
-Added Path to JsonReader/JsonWriter/ErrorContext with the JSON path of the current position
-Changed collection type on JsonArrayContract to public -Changed dictionary key type and dictionary value type on JsonDictionaryContract to public -Fixed error handling when failing to parse array content -Fixed error handling when there are missing required properties
-rw-r--r--Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs152
-rw-r--r--Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs163
-rw-r--r--Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs2
-rw-r--r--Src/Newtonsoft.Json.Tests/Serialization/SerializationErrorHandlingTests.cs93
-rw-r--r--Src/Newtonsoft.Json.Tests/TestObjects/VersionKeyedCollection.cs2
-rw-r--r--Src/Newtonsoft.Json/JsonReader.cs197
-rw-r--r--Src/Newtonsoft.Json/JsonWriter.cs197
-rw-r--r--Src/Newtonsoft.Json/Properties/AssemblyInfo.cs2
-rw-r--r--Src/Newtonsoft.Json/Serialization/ErrorContext.cs8
-rw-r--r--Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs7
-rw-r--r--Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs12
-rw-r--r--Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs8
-rw-r--r--Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs173
-rw-r--r--Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs6
14 files changed, 762 insertions, 260 deletions
diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs
index bda2f3e..3488f99 100644
--- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs
+++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs
@@ -272,75 +272,127 @@ namespace Newtonsoft.Json.Tests
{
string input = @"{
value:'Purple',
- array:[1,2],
- subobject:{prop:1}
+ array:[1,2,new Date(1)],
+ subobject:{prop:1,proparray:[1]}
}";
StringReader sr = new StringReader(input);
- using (JsonReader jsonReader = new JsonTextReader(sr))
+ using (JsonReader reader = new JsonTextReader(sr))
{
- Assert.AreEqual(0, jsonReader.Depth);
+ Assert.AreEqual(0, reader.Depth);
- jsonReader.Read();
- Assert.AreEqual(jsonReader.TokenType, JsonToken.StartObject);
- Assert.AreEqual(0, jsonReader.Depth);
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.StartObject);
+ Assert.AreEqual(0, reader.Depth);
+ Assert.AreEqual("", reader.Path);
- jsonReader.Read();
- Assert.AreEqual(jsonReader.TokenType, JsonToken.PropertyName);
- Assert.AreEqual(1, jsonReader.Depth);
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.PropertyName);
+ Assert.AreEqual(1, reader.Depth);
+ Assert.AreEqual("value", reader.Path);
- jsonReader.Read();
- Assert.AreEqual(jsonReader.TokenType, JsonToken.String);
- Assert.AreEqual(jsonReader.Value, @"Purple");
- Assert.AreEqual(jsonReader.QuoteChar, '\'');
- Assert.AreEqual(1, jsonReader.Depth);
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.String);
+ Assert.AreEqual(reader.Value, @"Purple");
+ Assert.AreEqual(reader.QuoteChar, '\'');
+ Assert.AreEqual(1, reader.Depth);
+ Assert.AreEqual("value", reader.Path);
- jsonReader.Read();
- Assert.AreEqual(jsonReader.TokenType, JsonToken.PropertyName);
- Assert.AreEqual(1, jsonReader.Depth);
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.PropertyName);
+ Assert.AreEqual(1, reader.Depth);
+ Assert.AreEqual("array", reader.Path);
- jsonReader.Read();
- Assert.AreEqual(jsonReader.TokenType, JsonToken.StartArray);
- Assert.AreEqual(1, jsonReader.Depth);
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.StartArray);
+ Assert.AreEqual(1, reader.Depth);
+ Assert.AreEqual("array", reader.Path);
- jsonReader.Read();
- Assert.AreEqual(jsonReader.TokenType, JsonToken.Integer);
- Assert.AreEqual(1, jsonReader.Value);
- Assert.AreEqual(2, jsonReader.Depth);
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.Integer);
+ Assert.AreEqual(1, reader.Value);
+ Assert.AreEqual(2, reader.Depth);
+ Assert.AreEqual("array[0]", reader.Path);
- jsonReader.Read();
- Assert.AreEqual(jsonReader.TokenType, JsonToken.Integer);
- Assert.AreEqual(2, jsonReader.Value);
- Assert.AreEqual(2, jsonReader.Depth);
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.Integer);
+ Assert.AreEqual(2, reader.Value);
+ Assert.AreEqual(2, reader.Depth);
+ Assert.AreEqual("array[1]", reader.Path);
- jsonReader.Read();
- Assert.AreEqual(jsonReader.TokenType, JsonToken.EndArray);
- Assert.AreEqual(1, jsonReader.Depth);
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.StartConstructor);
+ Assert.AreEqual("Date", reader.Value);
+ Assert.AreEqual(2, reader.Depth);
+ Assert.AreEqual("array[2]", reader.Path);
- jsonReader.Read();
- Assert.AreEqual(jsonReader.TokenType, JsonToken.PropertyName);
- Assert.AreEqual(1, jsonReader.Depth);
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.Integer);
+ Assert.AreEqual(1, reader.Value);
+ Assert.AreEqual(3, reader.Depth);
+ Assert.AreEqual("array[2][0]", reader.Path);
- jsonReader.Read();
- Assert.AreEqual(jsonReader.TokenType, JsonToken.StartObject);
- Assert.AreEqual(1, jsonReader.Depth);
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.EndConstructor);
+ Assert.AreEqual(null, reader.Value);
+ Assert.AreEqual(2, reader.Depth);
+ Assert.AreEqual("array[2]", reader.Path);
- jsonReader.Read();
- Assert.AreEqual(jsonReader.TokenType, JsonToken.PropertyName);
- Assert.AreEqual(2, jsonReader.Depth);
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.EndArray);
+ Assert.AreEqual(1, reader.Depth);
+ Assert.AreEqual("array", reader.Path);
- jsonReader.Read();
- Assert.AreEqual(jsonReader.TokenType, JsonToken.Integer);
- Assert.AreEqual(2, jsonReader.Depth);
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.PropertyName);
+ Assert.AreEqual(1, reader.Depth);
+ Assert.AreEqual("subobject", reader.Path);
- jsonReader.Read();
- Assert.AreEqual(jsonReader.TokenType, JsonToken.EndObject);
- Assert.AreEqual(1, jsonReader.Depth);
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.StartObject);
+ Assert.AreEqual(1, reader.Depth);
+ Assert.AreEqual("subobject", reader.Path);
- jsonReader.Read();
- Assert.AreEqual(jsonReader.TokenType, JsonToken.EndObject);
- Assert.AreEqual(0, jsonReader.Depth);
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.PropertyName);
+ Assert.AreEqual(2, reader.Depth);
+ Assert.AreEqual("subobject.prop", reader.Path);
+
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.Integer);
+ Assert.AreEqual(2, reader.Depth);
+ Assert.AreEqual("subobject.prop", reader.Path);
+
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.PropertyName);
+ Assert.AreEqual(2, reader.Depth);
+ Assert.AreEqual("subobject.proparray", reader.Path);
+
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.StartArray);
+ Assert.AreEqual(2, reader.Depth);
+ Assert.AreEqual("subobject.proparray", reader.Path);
+
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.Integer);
+ Assert.AreEqual(3, reader.Depth);
+ Assert.AreEqual("subobject.proparray[0]", reader.Path);
+
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.EndArray);
+ Assert.AreEqual(2, reader.Depth);
+ Assert.AreEqual("subobject.proparray", reader.Path);
+
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.EndObject);
+ Assert.AreEqual(1, reader.Depth);
+ Assert.AreEqual("subobject", reader.Path);
+
+ reader.Read();
+ Assert.AreEqual(reader.TokenType, JsonToken.EndObject);
+ Assert.AreEqual(0, reader.Depth);
+ Assert.AreEqual("", reader.Path);
}
}
diff --git a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs
index 614bd08..97323a1 100644
--- a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs
+++ b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs
@@ -200,6 +200,85 @@ namespace Newtonsoft.Json.Tests
}
[Test]
+ public void WriteEnd()
+ {
+ StringBuilder sb = new StringBuilder();
+ StringWriter sw = new StringWriter(sb);
+
+ using (JsonWriter jsonWriter = new JsonTextWriter(sw))
+ {
+ jsonWriter.Formatting = Formatting.Indented;
+
+ jsonWriter.WriteStartObject();
+ jsonWriter.WritePropertyName("CPU");
+ jsonWriter.WriteValue("Intel");
+ jsonWriter.WritePropertyName("PSU");
+ jsonWriter.WriteValue("500W");
+ jsonWriter.WritePropertyName("Drives");
+ jsonWriter.WriteStartArray();
+ jsonWriter.WriteValue("DVD read/writer");
+ jsonWriter.WriteComment("(broken)");
+ jsonWriter.WriteValue("500 gigabyte hard drive");
+ jsonWriter.WriteValue("200 gigabype hard drive");
+ jsonWriter.WriteEndObject();
+ Assert.AreEqual(WriteState.Start, jsonWriter.WriteState);
+ }
+
+ string expected = @"{
+ ""CPU"": ""Intel"",
+ ""PSU"": ""500W"",
+ ""Drives"": [
+ ""DVD read/writer""
+ /*(broken)*/,
+ ""500 gigabyte hard drive"",
+ ""200 gigabype hard drive""
+ ]
+}";
+ string result = sb.ToString();
+
+ Assert.AreEqual(expected, result);
+ }
+
+ [Test]
+ public void CloseWithRemainingContent()
+ {
+ StringBuilder sb = new StringBuilder();
+ StringWriter sw = new StringWriter(sb);
+
+ using (JsonWriter jsonWriter = new JsonTextWriter(sw))
+ {
+ jsonWriter.Formatting = Formatting.Indented;
+
+ jsonWriter.WriteStartObject();
+ jsonWriter.WritePropertyName("CPU");
+ jsonWriter.WriteValue("Intel");
+ jsonWriter.WritePropertyName("PSU");
+ jsonWriter.WriteValue("500W");
+ jsonWriter.WritePropertyName("Drives");
+ jsonWriter.WriteStartArray();
+ jsonWriter.WriteValue("DVD read/writer");
+ jsonWriter.WriteComment("(broken)");
+ jsonWriter.WriteValue("500 gigabyte hard drive");
+ jsonWriter.WriteValue("200 gigabype hard drive");
+ jsonWriter.Close();
+ }
+
+ string expected = @"{
+ ""CPU"": ""Intel"",
+ ""PSU"": ""500W"",
+ ""Drives"": [
+ ""DVD read/writer""
+ /*(broken)*/,
+ ""500 gigabyte hard drive"",
+ ""200 gigabype hard drive""
+ ]
+}";
+ string result = sb.ToString();
+
+ Assert.AreEqual(expected, result);
+ }
+
+ [Test]
public void Indenting()
{
StringBuilder sb = new StringBuilder();
@@ -222,6 +301,7 @@ namespace Newtonsoft.Json.Tests
jsonWriter.WriteValue("200 gigabype hard drive");
jsonWriter.WriteEnd();
jsonWriter.WriteEndObject();
+ Assert.AreEqual(WriteState.Start, jsonWriter.WriteState);
}
// {
@@ -247,9 +327,6 @@ namespace Newtonsoft.Json.Tests
}";
string result = sb.ToString();
- Console.WriteLine("Indenting");
- Console.WriteLine(result);
-
Assert.AreEqual(expected, result);
}
@@ -265,27 +342,34 @@ namespace Newtonsoft.Json.Tests
jsonWriter.WriteStartObject();
Assert.AreEqual(WriteState.Object, jsonWriter.WriteState);
+ Assert.AreEqual("", jsonWriter.Path);
jsonWriter.WritePropertyName("CPU");
Assert.AreEqual(WriteState.Property, jsonWriter.WriteState);
+ Assert.AreEqual("CPU", jsonWriter.Path);
jsonWriter.WriteValue("Intel");
Assert.AreEqual(WriteState.Object, jsonWriter.WriteState);
+ Assert.AreEqual("CPU", jsonWriter.Path);
jsonWriter.WritePropertyName("Drives");
Assert.AreEqual(WriteState.Property, jsonWriter.WriteState);
+ Assert.AreEqual("Drives", jsonWriter.Path);
jsonWriter.WriteStartArray();
Assert.AreEqual(WriteState.Array, jsonWriter.WriteState);
jsonWriter.WriteValue("DVD read/writer");
Assert.AreEqual(WriteState.Array, jsonWriter.WriteState);
+ Assert.AreEqual("Drives[0]", jsonWriter.Path);
jsonWriter.WriteEnd();
Assert.AreEqual(WriteState.Object, jsonWriter.WriteState);
+ Assert.AreEqual("Drives", jsonWriter.Path);
jsonWriter.WriteEndObject();
Assert.AreEqual(WriteState.Start, jsonWriter.WriteState);
+ Assert.AreEqual("", jsonWriter.Path);
}
}
@@ -621,6 +705,79 @@ _____'propertyName': NaN
}
[Test]
+ public void Path()
+ {
+ StringBuilder sb = new StringBuilder();
+ StringWriter sw = new StringWriter(sb);
+
+ string text = "Hello world.";
+ byte[] data = Encoding.UTF8.GetBytes(text);
+
+ using (JsonTextWriter writer = new JsonTextWriter(sw))
+ {
+ writer.Formatting = Formatting.Indented;
+
+ writer.WriteStartArray();
+ Assert.AreEqual("", writer.Path);
+ writer.WriteStartObject();
+ Assert.AreEqual("[0]", writer.Path);
+ writer.WritePropertyName("Property1");
+ Assert.AreEqual("[0].Property1", writer.Path);
+ writer.WriteStartArray();
+ Assert.AreEqual("[0].Property1", writer.Path);
+ writer.WriteValue(1);
+ Assert.AreEqual("[0].Property1[0]", writer.Path);
+ writer.WriteStartArray();
+ Assert.AreEqual("[0].Property1[1]", writer.Path);
+ writer.WriteStartArray();
+ Assert.AreEqual("[0].Property1[1][0]", writer.Path);
+ writer.WriteStartArray();
+ Assert.AreEqual("[0].Property1[1][0][0]", writer.Path);
+ writer.WriteEndObject();
+ Assert.AreEqual("[0]", writer.Path);
+ writer.WriteStartObject();
+ Assert.AreEqual("[1]", writer.Path);
+ writer.WritePropertyName("Property2");
+ Assert.AreEqual("[1].Property2", writer.Path);
+ writer.WriteStartConstructor("Constructor1");
+ Assert.AreEqual("[1].Property2", writer.Path);
+ writer.WriteNull();
+ Assert.AreEqual("[1].Property2[0]", writer.Path);
+ writer.WriteStartArray();
+ Assert.AreEqual("[1].Property2[1]", writer.Path);
+ writer.WriteValue(1);
+ Assert.AreEqual("[1].Property2[1][0]", writer.Path);
+ writer.WriteEnd();
+ Assert.AreEqual("[1].Property2[1]", writer.Path);
+ writer.WriteEndObject();
+ Assert.AreEqual("[1]", writer.Path);
+ writer.WriteEndArray();
+ Assert.AreEqual("", writer.Path);
+ }
+
+ Assert.AreEqual(@"[
+ {
+ ""Property1"": [
+ 1,
+ [
+ [
+ []
+ ]
+ ]
+ ]
+ },
+ {
+ ""Property2"": new Constructor1(
+ null,
+ [
+ 1
+ ]
+ )
+ }
+]", sb.ToString());
+ }
+
+ [Test]
public void BuildStateArray()
{
JsonWriter.State[][] stateArray = JsonWriter.BuildStateArray();
diff --git a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs
index 6c451eb..f34065e 100644
--- a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs
+++ b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs
@@ -72,5 +72,5 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.0.8.0")]
#if !PocketPC
-[assembly: AssemblyFileVersion("4.0.8.14618")]
+[assembly: AssemblyFileVersion("4.0.8.14623")]
#endif
diff --git a/Src/Newtonsoft.Json.Tests/Serialization/SerializationErrorHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/SerializationErrorHandlingTests.cs
index 61e76d8..a6a4ec5 100644
--- a/Src/Newtonsoft.Json.Tests/Serialization/SerializationErrorHandlingTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Serialization/SerializationErrorHandlingTests.cs
@@ -57,7 +57,7 @@ namespace Newtonsoft.Json.Tests.Serialization
VersionKeyedCollection c = JsonConvert.DeserializeObject<VersionKeyedCollection>(json);
Assert.AreEqual(1, c.Count);
Assert.AreEqual(1, c.Messages.Count);
- Assert.AreEqual("Error message for member 1 = An item with the same key has already been added.", c.Messages[0]);
+ Assert.AreEqual("[1] - Error message for member 1 = An item with the same key has already been added.", c.Messages[0]);
}
[Test]
@@ -161,7 +161,8 @@ namespace Newtonsoft.Json.Tests.Serialization
{
List<string> errors = new List<string>();
- List<DateTime> c = JsonConvert.DeserializeObject<List<DateTime>>(@"[
+ List<DateTime> c = JsonConvert.DeserializeObject<List<DateTime>>(
+ @"[
""2009-09-09T00:00:00Z"",
""I am not a date and will error!"",
[
@@ -175,10 +176,10 @@ namespace Newtonsoft.Json.Tests.Serialization
{
Error = delegate(object sender, ErrorEventArgs args)
{
- errors.Add(args.ErrorContext.Error.Message);
+ errors.Add(args.ErrorContext.Path + " - " + args.ErrorContext.Member + " - " + args.ErrorContext.Error.Message);
args.ErrorContext.Handled = true;
},
- Converters = { new IsoDateTimeConverter() }
+ Converters = {new IsoDateTimeConverter()}
});
// 2009-09-09T00:00:00Z
@@ -196,12 +197,12 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.AreEqual(3, errors.Count);
#if !(NET20 || NET35 || WINDOWS_PHONE)
- Assert.AreEqual("The string was not recognized as a valid DateTime. There is an unknown word starting at index 0.", errors[0]);
+ Assert.AreEqual("[1] - 1 - The string was not recognized as a valid DateTime. There is an unknown word starting at index 0.", errors[0]);
#else
- Assert.AreEqual("The string was not recognized as a valid DateTime. There is a unknown word starting at index 0.", errors[0]);
+ Assert.AreEqual("[1] - 1 - The string was not recognized as a valid DateTime. There is a unknown word starting at index 0.", errors[0]);
#endif
- Assert.AreEqual("Unexpected token parsing date. Expected String, got StartArray.", errors[1]);
- Assert.AreEqual("Cannot convert null value to System.DateTime.", errors[2]);
+ Assert.AreEqual("[2] - 2 - Unexpected token parsing date. Expected String, got StartArray.", errors[1]);
+ Assert.AreEqual("[4] - 4 - Cannot convert null value to System.DateTime.", errors[2]);
}
[Test]
@@ -209,7 +210,8 @@ namespace Newtonsoft.Json.Tests.Serialization
{
bool eventErrorHandlerCalled = false;
- DateTimeErrorObjectCollection c = JsonConvert.DeserializeObject<DateTimeErrorObjectCollection>(@"[
+ DateTimeErrorObjectCollection c = JsonConvert.DeserializeObject<DateTimeErrorObjectCollection>(
+ @"[
""2009-09-09T00:00:00Z"",
""kjhkjhkjhkjh"",
[
@@ -220,13 +222,13 @@ namespace Newtonsoft.Json.Tests.Serialization
""2000-12-01T00:00:00Z""
]",
new JsonSerializerSettings
- {
- Error = (s, a) => eventErrorHandlerCalled = true,
- Converters =
+ {
+ Error = (s, a) => eventErrorHandlerCalled = true,
+ Converters =
{
new IsoDateTimeConverter()
}
- });
+ });
Assert.AreEqual(3, c.Count);
Assert.AreEqual(new DateTime(2009, 9, 9, 0, 0, 0, DateTimeKind.Utc), c[0]);
@@ -270,25 +272,76 @@ namespace Newtonsoft.Json.Tests.Serialization
string json = @"[[""kjhkjhkjhkjh""]]";
+ Exception e = null;
try
{
JsonSerializer serializer = new JsonSerializer();
serializer.Error += delegate(object sender, ErrorEventArgs args)
- {
- // only log an error once
- if (args.CurrentObject == args.ErrorContext.OriginalObject)
- errors.Add(args.ErrorContext.Error.Message);
- };
+ {
+ // only log an error once
+ if (args.CurrentObject == args.ErrorContext.OriginalObject)
+ errors.Add(args.ErrorContext.Path + " - " + args.ErrorContext.Member + " - " + args.ErrorContext.Error.Message);
+ };
serializer.Deserialize(new StringReader(json), typeof(List<List<DateTime>>));
}
catch (Exception ex)
{
- Console.WriteLine(ex.Message);
+ e = ex;
}
+ Assert.AreEqual(@"Error converting value ""kjhkjhkjhkjh"" to type 'System.DateTime'. Line 1, position 16.", e.Message);
+
Assert.AreEqual(1, errors.Count);
- Assert.AreEqual(@"Error converting value ""kjhkjhkjhkjh"" to type 'System.DateTime'. Line 1, position 16.", errors[0]);
+ Assert.AreEqual(@"[0][0] - 0 - Error converting value ""kjhkjhkjhkjh"" to type 'System.DateTime'. Line 1, position 16.", errors[0]);
+ }
+
+ [Test]
+ public void MultipleRequiredPropertyErrors()
+ {
+ string json = "{}";
+ List<string> errors = new List<string>();
+ JsonSerializer serializer = new JsonSerializer();
+ serializer.Error += delegate(object sender, ErrorEventArgs args)
+ {
+ errors.Add(args.ErrorContext.Path + " - " + args.ErrorContext.Member + " - " + args.ErrorContext.Error.Message);
+ args.ErrorContext.Handled = true;
+ };
+ serializer.Deserialize(new JsonTextReader(new StringReader(json)), typeof (MyTypeWithRequiredMembers));
+
+ Assert.AreEqual(2, errors.Count);
+ Assert.AreEqual(" - Required1 - Required property 'Required1' not found in JSON. Line 1, position 2.", errors[0]);
+ Assert.AreEqual(" - Required2 - Required property 'Required2' not found in JSON. Line 1, position 2.", errors[1]);
+ }
+
+ [Test]
+ public void HandlingArrayErrors()
+ {
+ string json = "[\"a\",\"b\",\"45\",34]";
+
+ List<string> errors = new List<string>();
+
+ JsonSerializer serializer = new JsonSerializer();
+ serializer.Error += delegate(object sender, ErrorEventArgs args)
+ {
+ errors.Add(args.ErrorContext.Path + " - " + args.ErrorContext.Member + " - " + args.ErrorContext.Error.Message);
+ args.ErrorContext.Handled = true;
+ };
+
+ serializer.Deserialize(new JsonTextReader(new StringReader(json)), typeof(int[]));
+
+ Assert.AreEqual(2, errors.Count);
+ Assert.AreEqual("[0] - 0 - Could not convert string to integer: a. Line 1, position 4.", errors[0]);
+ Assert.AreEqual("[1] - 1 - Could not convert string to integer: b. Line 1, position 8.", errors[1]);
}
}
+
+ [JsonObject]
+ public class MyTypeWithRequiredMembers
+ {
+ [JsonProperty(Required = Required.AllowNull)]
+ public string Required1;
+ [JsonProperty(Required = Required.AllowNull)]
+ public string Required2;
+ }
} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/VersionKeyedCollection.cs b/Src/Newtonsoft.Json.Tests/TestObjects/VersionKeyedCollection.cs
index 647b29a..66a84d6 100644
--- a/Src/Newtonsoft.Json.Tests/TestObjects/VersionKeyedCollection.cs
+++ b/Src/Newtonsoft.Json.Tests/TestObjects/VersionKeyedCollection.cs
@@ -50,7 +50,7 @@ namespace Newtonsoft.Json.Tests.TestObjects
[OnError]
internal void OnErrorMethod(StreamingContext context, ErrorContext errorContext)
{
- Messages.Add("Error message for member " + errorContext.Member + " = " + errorContext.Error.Message);
+ Messages.Add(errorContext.Path + " - Error message for member " + errorContext.Member + " = " + errorContext.Error.Message);
errorContext.Handled = true;
}
diff --git a/Src/Newtonsoft.Json/JsonReader.cs b/Src/Newtonsoft.Json/JsonReader.cs
index 6d80c6e..edcc989 100644
--- a/Src/Newtonsoft.Json/JsonReader.cs
+++ b/Src/Newtonsoft.Json/JsonReader.cs
@@ -27,11 +27,78 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Globalization;
+using System.Linq;
+using System.Text;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json
{
+ internal enum JsonContainerType
+ {
+ None,
+ Object,
+ Array,
+ Constructor
+ }
+
+ internal struct JsonPosition
+ {
+ internal JsonContainerType Type;
+ internal int? Position;
+ internal string PropertyName;
+
+ internal void WriteTo(StringBuilder sb)
+ {
+ switch (Type)
+ {
+ case JsonContainerType.Object:
+ if (PropertyName != null)
+ {
+ if (sb.Length > 0)
+ sb.Append(".");
+ sb.Append(PropertyName);
+ }
+ break;
+ case JsonContainerType.Array:
+ case JsonContainerType.Constructor:
+ if (Position != null)
+ {
+ sb.Append("[");
+ sb.Append(Position);
+ sb.Append("]");
+ }
+ break;
+ }
+ }
+
+ internal bool InsideContainer()
+ {
+ switch (Type)
+ {
+ case JsonContainerType.Object:
+ return (PropertyName != null);
+ case JsonContainerType.Array:
+ case JsonContainerType.Constructor:
+ return (Position != null);
+ }
+
+ return false;
+ }
+
+ internal static string BuildPath(IEnumerable<JsonPosition> positions)
+ {
+ StringBuilder sb = new StringBuilder();
+
+ foreach (JsonPosition state in positions)
+ {
+ state.WriteTo(sb);
+ }
+
+ return sb.ToString();
+ }
+ }
+
/// <summary>
/// Represents a reader that provides fast, non-cached, forward-only access to serialized Json data.
/// </summary>
@@ -101,7 +168,7 @@ namespace Newtonsoft.Json
private object _value;
private char _quoteChar;
internal State _currentState;
- private JTokenType _currentTypeContext;
+ private JsonPosition _currentPosition;
private CultureInfo _culture;
/// <summary>
@@ -113,9 +180,7 @@ namespace Newtonsoft.Json
get { return _currentState; }
}
- private int _top;
-
- private readonly List<JTokenType> _stack;
+ private readonly List<JsonPosition> _stack;
/// <summary>
/// Gets or sets a value indicating whether the underlying stream or
@@ -137,7 +202,7 @@ namespace Newtonsoft.Json
}
/// <summary>
- /// Gets the type of the current Json token.
+ /// Gets the type of the current JSON token.
/// </summary>
public virtual JsonToken TokenType
{
@@ -145,7 +210,7 @@ namespace Newtonsoft.Json
}
/// <summary>
- /// Gets the text value of the current Json token.
+ /// Gets the text value of the current JSON token.
/// </summary>
public virtual object Value
{
@@ -153,7 +218,7 @@ namespace Newtonsoft.Json
}
/// <summary>
- /// Gets The Common Language Runtime (CLR) type for the current Json token.
+ /// Gets The Common Language Runtime (CLR) type for the current JSON token.
/// </summary>
public virtual Type ValueType
{
@@ -168,11 +233,11 @@ namespace Newtonsoft.Json
{
get
{
- int depth = _top - 1;
- if (IsStartToken(TokenType))
- return depth - 1;
- else
+ int depth = _stack.Count;
+ if (IsStartToken(TokenType) || _currentPosition.Type == JsonContainerType.None)
return depth;
+ else
+ return depth + 1;
}
}
@@ -186,38 +251,70 @@ namespace Newtonsoft.Json
}
/// <summary>
+ /// Gets the path of the current JSON token.
+ /// </summary>
+ public string Path
+ {
+ get
+ {
+ if (_currentPosition.Type == JsonContainerType.None)
+ return string.Empty;
+
+ return JsonPosition.BuildPath(_stack.Concat(new[] { _currentPosition }));
+ }
+ }
+
+ /// <summary>
/// Initializes a new instance of the <see cref="JsonReader"/> class with the specified <see cref="TextReader"/>.
/// </summary>
protected JsonReader()
{
_currentState = State.Start;
- _stack = new List<JTokenType>();
+ _stack = new List<JsonPosition>(4);
CloseInput = true;
-
- Push(JTokenType.None);
}
- private void Push(JTokenType value)
+ private void Push(JsonContainerType value)
{
- _stack.Add(value);
- _top++;
- _currentTypeContext = value;
+ UpdateScopeWithFinishedValue();
+
+ if (_currentPosition.Type == JsonContainerType.None)
+ {
+ _currentPosition.Type = value;
+ }
+ else
+ {
+ _stack.Add(_currentPosition);
+ var state = new JsonPosition
+ {
+ Type = value
+ };
+ _currentPosition = state;
+ }
}
- private JTokenType Pop()
+ private JsonContainerType Pop()
{
- JTokenType value = Peek();
- _stack.RemoveAt(_stack.Count - 1);
- _top--;
- _currentTypeContext = _stack[_top - 1];
+ JsonPosition oldPosition;
+ if (_stack.Count > 0)
+ {
+ oldPosition = _currentPosition;
+ _currentPosition = _stack[_stack.Count - 1];
+ _stack.RemoveAt(_stack.Count - 1);
+ }
+ else
+ {
+ oldPosition = _currentPosition;
+ _currentPosition = new JsonPosition();
+ }
- return value;
+ return oldPosition.Type;
}
- private JTokenType Peek()
+ private JsonContainerType Peek()
{
- return _currentTypeContext;
+ return _currentPosition.Type;
}
/// <summary>
@@ -292,15 +389,15 @@ namespace Newtonsoft.Json
{
case JsonToken.StartObject:
_currentState = State.ObjectStart;
- Push(JTokenType.Object);
+ Push(JsonContainerType.Object);
break;
case JsonToken.StartArray:
_currentState = State.ArrayStart;
- Push(JTokenType.Array);
+ Push(JsonContainerType.Array);
break;
case JsonToken.StartConstructor:
_currentState = State.ConstructorStart;
- Push(JTokenType.Constructor);
+ Push(JsonContainerType.Constructor);
break;
case JsonToken.EndObject:
ValidateEnd(JsonToken.EndObject);
@@ -313,6 +410,8 @@ namespace Newtonsoft.Json
break;
case JsonToken.PropertyName:
_currentState = State.Property;
+
+ _currentPosition.PropertyName = (string) value;
break;
case JsonToken.Undefined:
case JsonToken.Integer:
@@ -323,21 +422,35 @@ namespace Newtonsoft.Json
case JsonToken.String:
case JsonToken.Raw:
case JsonToken.Bytes:
- _currentState = (Peek() != JTokenType.None) ? State.PostValue : State.Finished;
+ _currentState = (Peek() != JsonContainerType.None) ? State.PostValue : State.Finished;
+
+ UpdateScopeWithFinishedValue();
break;
}
_value = value;
}
+ private void UpdateScopeWithFinishedValue()
+ {
+ if (_currentPosition.Type == JsonContainerType.Array
+ || _currentPosition.Type == JsonContainerType.Constructor)
+ {
+ if (_currentPosition.Position == null)
+ _currentPosition.Position = 0;
+ else
+ _currentPosition.Position++;
+ }
+ }
+
private void ValidateEnd(JsonToken endToken)
{
- JTokenType currentObject = Pop();
+ JsonContainerType currentObject = Pop();
if (GetTypeForCloseToken(endToken) != currentObject)
throw new JsonReaderException("JsonToken {0} is not valid for closing JsonType {1}.".FormatWith(CultureInfo.InvariantCulture, endToken, currentObject));
- _currentState = (Peek() != JTokenType.None) ? State.PostValue : State.Finished;
+ _currentState = (Peek() != JsonContainerType.None) ? State.PostValue : State.Finished;
}
/// <summary>
@@ -345,20 +458,20 @@ namespace Newtonsoft.Json
/// </summary>
protected void SetStateBasedOnCurrent()
{
- JTokenType currentObject = Peek();
+ JsonContainerType currentObject = Peek();
switch (currentObject)
{
- case JTokenType.Object:
+ case JsonContainerType.Object:
_currentState = State.Object;
break;
- case JTokenType.Array:
+ case JsonContainerType.Array:
_currentState = State.Array;
break;
- case JTokenType.Constructor:
+ case JsonContainerType.Constructor:
_currentState = State.Constructor;
break;
- case JTokenType.None:
+ case JsonContainerType.None:
_currentState = State.Finished;
break;
default:
@@ -413,16 +526,16 @@ namespace Newtonsoft.Json
}
}
- private JTokenType GetTypeForCloseToken(JsonToken token)
+ private JsonContainerType GetTypeForCloseToken(JsonToken token)
{
switch (token)
{
case JsonToken.EndObject:
- return JTokenType.Object;
+ return JsonContainerType.Object;
case JsonToken.EndArray:
- return JTokenType.Array;
+ return JsonContainerType.Array;
case JsonToken.EndConstructor:
- return JTokenType.Constructor;
+ return JsonContainerType.Constructor;
default:
throw new JsonReaderException("Not a valid close JsonToken: {0}".FormatWith(CultureInfo.InvariantCulture, token));
}
@@ -497,4 +610,4 @@ namespace Newtonsoft.Json
return message;
}
}
-}
+} \ No newline at end of file
diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs
index aa77b0f..a4e9289 100644
--- a/Src/Newtonsoft.Json/JsonWriter.cs
+++ b/Src/Newtonsoft.Json/JsonWriter.cs
@@ -160,9 +160,8 @@ namespace Newtonsoft.Json
StateArray = BuildStateArray();
}
- private int _top;
-
- private readonly List<JTokenType> _stack;
+ private readonly List<JsonPosition> _stack;
+ private JsonPosition _currentPosition;
private State _currentState;
private Formatting _formatting;
@@ -182,9 +181,31 @@ namespace Newtonsoft.Json
/// <value>The top.</value>
protected internal int Top
{
- get { return _top; }
+ get
+ {
+ int depth = _stack.Count;
+ if (Peek() != JsonContainerType.None)
+ depth++;
+
+ return depth;
+ }
}
+ internal string ContainerPath
+ {
+ get
+ {
+ if (_currentPosition.Type == JsonContainerType.None)
+ return string.Empty;
+
+ IEnumerable<JsonPosition> positions = (_currentPosition.InsideContainer())
+ ? _stack
+ : _stack.Concat(new[] { _currentPosition });
+
+ return JsonPosition.BuildPath(positions);
+ }
+ }
+
/// <summary>
/// Gets the state of the writer.
/// </summary>
@@ -218,6 +239,20 @@ namespace Newtonsoft.Json
}
/// <summary>
+ /// Gets the path of the writer.
+ /// </summary>
+ public string Path
+ {
+ get
+ {
+ if (_currentPosition.Type == JsonContainerType.None)
+ return string.Empty;
+
+ return JsonPosition.BuildPath(_stack.Concat(new[] { _currentPosition }));
+ }
+ }
+
+ /// <summary>
/// Indicates how the output is formatted.
/// </summary>
public Formatting Formatting
@@ -231,34 +266,65 @@ namespace Newtonsoft.Json
/// </summary>
protected JsonWriter()
{
- _stack = new List<JTokenType>(8);
- _stack.Add(JTokenType.None);
+ _stack = new List<JsonPosition>(4);
_currentState = State.Start;
_formatting = Formatting.None;
CloseOutput = true;
}
- private void Push(JTokenType value)
+ private void UpdateScopeWithFinishedValue()
+ {
+ if (_currentPosition.Type == JsonContainerType.Array
+ || _currentPosition.Type == JsonContainerType.Constructor)
+ {
+ if (_currentPosition.Position == null)
+ _currentPosition.Position = 0;
+ else
+ _currentPosition.Position++;
+ }
+ }
+
+ private void Push(JsonContainerType value)
{
- _top++;
- if (_stack.Count <= _top)
- _stack.Add(value);
+ UpdateScopeWithFinishedValue();
+
+ if (_currentPosition.Type == JsonContainerType.None)
+ {
+ _currentPosition.Type = value;
+ }
else
- _stack[_top] = value;
+ {
+ _stack.Add(_currentPosition);
+ var state = new JsonPosition
+ {
+ Type = value
+ };
+ _currentPosition = state;
+ }
}
- private JTokenType Pop()
+ private JsonContainerType Pop()
{
- JTokenType value = Peek();
- _top--;
+ JsonPosition oldPosition;
+ if (_stack.Count > 0)
+ {
+ oldPosition = _currentPosition;
+ _currentPosition = _stack[_stack.Count - 1];
+ _stack.RemoveAt(_stack.Count - 1);
+ }
+ else
+ {
+ oldPosition = _currentPosition;
+ _currentPosition = new JsonPosition();
+ }
- return value;
+ return oldPosition.Type;
}
- private JTokenType Peek()
+ private JsonContainerType Peek()
{
- return _stack[_top];
+ return _currentPosition.Type;
}
/// <summary>
@@ -280,7 +346,7 @@ namespace Newtonsoft.Json
public virtual void WriteStartObject()
{
AutoComplete(JsonToken.StartObject);
- Push(JTokenType.Object);
+ Push(JsonContainerType.Object);
}
/// <summary>
@@ -297,7 +363,7 @@ namespace Newtonsoft.Json
public virtual void WriteStartArray()
{
AutoComplete(JsonToken.StartArray);
- Push(JTokenType.Array);
+ Push(JsonContainerType.Array);
}
/// <summary>
@@ -315,7 +381,7 @@ namespace Newtonsoft.Json
public virtual void WriteStartConstructor(string name)
{
AutoComplete(JsonToken.StartConstructor);
- Push(JTokenType.Constructor);
+ Push(JsonContainerType.Constructor);
}
/// <summary>
@@ -332,6 +398,7 @@ namespace Newtonsoft.Json
/// <param name="name">The name of the property.</param>
public virtual void WritePropertyName(string name)
{
+ _currentPosition.PropertyName = name;
AutoComplete(JsonToken.PropertyName);
}
@@ -482,17 +549,17 @@ namespace Newtonsoft.Json
}
}
- private void WriteEnd(JTokenType type)
+ private void WriteEnd(JsonContainerType type)
{
switch (type)
{
- case JTokenType.Object:
+ case JsonContainerType.Object:
WriteEndObject();
break;
- case JTokenType.Array:
+ case JsonContainerType.Array:
WriteEndArray();
break;
- case JTokenType.Constructor:
+ case JsonContainerType.Constructor:
WriteEndConstructor();
break;
default:
@@ -502,36 +569,36 @@ namespace Newtonsoft.Json
private void AutoCompleteAll()
{
- while (_top > 0)
+ while (Top > 0)
{
WriteEnd();
}
}
- private JTokenType GetTypeForCloseToken(JsonToken token)
+ private JsonContainerType GetTypeForCloseToken(JsonToken token)
{
switch (token)
{
case JsonToken.EndObject:
- return JTokenType.Object;
+ return JsonContainerType.Object;
case JsonToken.EndArray:
- return JTokenType.Array;
+ return JsonContainerType.Array;
case JsonToken.EndConstructor:
- return JTokenType.Constructor;
+ return JsonContainerType.Constructor;
default:
throw new JsonWriterException("No type for token: " + token);
}
}
- private JsonToken GetCloseTokenForType(JTokenType type)
+ private JsonToken GetCloseTokenForType(JsonContainerType type)
{
switch (type)
{
- case JTokenType.Object:
+ case JsonContainerType.Object:
return JsonToken.EndObject;
- case JTokenType.Array:
+ case JsonContainerType.Array:
return JsonToken.EndArray;
- case JTokenType.Constructor:
+ case JsonContainerType.Constructor:
return JsonToken.EndConstructor;
default:
throw new JsonWriterException("No close token for type: " + type);
@@ -543,15 +610,24 @@ namespace Newtonsoft.Json
// write closing symbol and calculate new state
int levelsToComplete = 0;
+ JsonContainerType type = GetTypeForCloseToken(tokenBeingClosed);
- for (int i = 0; i < _top; i++)
+ if (_currentPosition.Type == type)
{
- int currentLevel = _top - i;
-
- if (_stack[currentLevel] == GetTypeForCloseToken(tokenBeingClosed))
+ levelsToComplete = 1;
+ }
+ else
+ {
+ int top = Top - 2;
+ for (int i = top; i >= 0; i--)
{
- levelsToComplete = i + 1;
- break;
+ int currentLevel = top - i;
+
+ if (_stack[currentLevel].Type == type)
+ {
+ levelsToComplete = i + 2;
+ break;
+ }
}
}
@@ -569,26 +645,26 @@ namespace Newtonsoft.Json
}
WriteEnd(token);
- }
- JTokenType currentLevelType = Peek();
+ JsonContainerType currentLevelType = Peek();
- switch (currentLevelType)
- {
- case JTokenType.Object:
- _currentState = State.Object;
- break;
- case JTokenType.Array:
- _currentState = State.Array;
- break;
- case JTokenType.Constructor:
- _currentState = State.Array;
- break;
- case JTokenType.None:
- _currentState = State.Start;
- break;
- default:
- throw new JsonWriterException("Unknown JsonType: " + currentLevelType);
+ switch (currentLevelType)
+ {
+ case JsonContainerType.Object:
+ _currentState = State.Object;
+ break;
+ case JsonContainerType.Array:
+ _currentState = State.Array;
+ break;
+ case JsonContainerType.Constructor:
+ _currentState = State.Array;
+ break;
+ case JsonContainerType.None:
+ _currentState = State.Start;
+ break;
+ default:
+ throw new JsonWriterException("Unknown JsonType: " + currentLevelType);
+ }
}
}
@@ -623,11 +699,18 @@ namespace Newtonsoft.Json
internal void AutoComplete(JsonToken tokenBeingWritten)
{
+ if (tokenBeingWritten != JsonToken.StartObject
+ && tokenBeingWritten != JsonToken.StartArray
+ && tokenBeingWritten != JsonToken.StartConstructor)
+ UpdateScopeWithFinishedValue();
+
// gets new state based on the current state and what is being written
State newState = StateArray[(int)tokenBeingWritten][(int)_currentState];
if (newState == State.Error)
+ {
throw new JsonWriterException("Token {0} in state {1} would result in an invalid JSON object.".FormatWith(CultureInfo.InvariantCulture, tokenBeingWritten.ToString(), _currentState.ToString()));
+ }
if ((_currentState == State.Object || _currentState == State.Array || _currentState == State.Constructor) && tokenBeingWritten != JsonToken.Comment)
{
diff --git a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs
index 8256f4f..b1bc331 100644
--- a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs
+++ b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs
@@ -85,7 +85,7 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.0.8.0")]
#if !PocketPC
-[assembly: AssemblyFileVersion("4.0.8.14618")]
+[assembly: AssemblyFileVersion("4.0.8.14623")]
#endif
[assembly: CLSCompliant(true)]
diff --git a/Src/Newtonsoft.Json/Serialization/ErrorContext.cs b/Src/Newtonsoft.Json/Serialization/ErrorContext.cs
index 2756d93..28f7ad5 100644
--- a/Src/Newtonsoft.Json/Serialization/ErrorContext.cs
+++ b/Src/Newtonsoft.Json/Serialization/ErrorContext.cs
@@ -35,11 +35,12 @@ namespace Newtonsoft.Json.Serialization
/// </summary>
public class ErrorContext
{
- internal ErrorContext(object originalObject, object member, Exception error)
+ internal ErrorContext(object originalObject, object member, string path, Exception error)
{
OriginalObject = originalObject;
Member = member;
Error = error;
+ Path = path;
}
/// <summary>
@@ -58,6 +59,11 @@ namespace Newtonsoft.Json.Serialization
/// <value>The member that caused the error.</value>
public object Member { get; private set; }
/// <summary>
+ /// Gets the path of the JSON location when the error occurred.
+ /// </summary>
+ /// <value>The path of the JSON location when the error occurred.</value>
+ public string Path { get; private set; }
+ /// <summary>
/// Gets or sets a value indicating whether this <see cref="ErrorContext"/> is handled.
/// </summary>
/// <value><c>true</c> if handled; otherwise, <c>false</c>.</value>
diff --git a/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs b/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs
index 7fd8b74..3204484 100644
--- a/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs
+++ b/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs
@@ -37,7 +37,12 @@ namespace Newtonsoft.Json.Serialization
/// </summary>
public class JsonArrayContract : JsonContract
{
- internal Type CollectionItemType { get; private set; }
+ /// <summary>
+ /// Gets the <see cref="Type"/> of the collection items.
+ /// </summary>
+ /// <value>The <see cref="Type"/> of the collection items.</value>
+ public Type CollectionItemType { get; private set; }
+
internal JsonContract CollectionItemContract { get; set; }
private readonly bool _isCollectionItemTypeNullableType;
diff --git a/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs b/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs
index 975c937..c3af3f3 100644
--- a/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs
+++ b/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs
@@ -42,8 +42,16 @@ namespace Newtonsoft.Json.Serialization
/// <value>The property name resolver.</value>
public Func<string, string> PropertyNameResolver { get; set; }
- internal Type DictionaryKeyType { get; private set; }
- internal Type DictionaryValueType { get; private set; }
+ /// <summary>
+ /// Gets the <see cref="Type"/> of the dictionary keys.
+ /// </summary>
+ /// <value>The <see cref="Type"/> of the dictionary keys.</value>
+ public Type DictionaryKeyType { get; private set; }
+ /// <summary>
+ /// Gets the <see cref="Type"/> of the dictionary values.
+ /// </summary>
+ /// <value>The <see cref="Type"/> of the dictionary values.</value>
+ public Type DictionaryValueType { get; private set; }
internal JsonContract DictionaryKeyContract { get; set; }
internal JsonContract DictionaryValueContract { get; set; }
diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs
index 761fa76..1c51346 100644
--- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs
+++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs
@@ -79,10 +79,10 @@ namespace Newtonsoft.Json.Serialization
}
}
- protected ErrorContext GetErrorContext(object currentObject, object member, Exception error)
+ protected ErrorContext GetErrorContext(object currentObject, object member, string path, Exception error)
{
if (_currentErrorContext == null)
- _currentErrorContext = new ErrorContext(currentObject, member, error);
+ _currentErrorContext = new ErrorContext(currentObject, member, path, error);
if (_currentErrorContext.Error != error)
throw new InvalidOperationException("Current error context error is different to requested error.");
@@ -98,9 +98,9 @@ namespace Newtonsoft.Json.Serialization
_currentErrorContext = null;
}
- protected bool IsErrorHandled(object currentObject, JsonContract contract, object keyValue, Exception ex)
+ protected bool IsErrorHandled(object currentObject, JsonContract contract, object keyValue, string path, Exception ex)
{
- ErrorContext errorContext = GetErrorContext(currentObject, keyValue, ex);
+ ErrorContext errorContext = GetErrorContext(currentObject, keyValue, path, ex);
contract.InvokeOnError(currentObject, Serializer.Context, errorContext);
if (!errorContext.Handled)
diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs
index 2957578..40054cc 100644
--- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs
+++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs
@@ -712,7 +712,7 @@ namespace Newtonsoft.Json.Serialization
}
catch (Exception ex)
{
- if (IsErrorHandled(dictionary, contract, keyValue, ex))
+ if (IsErrorHandled(dictionary, contract, keyValue, reader.Path, ex))
HandleError(reader, initialDepth);
else
throw;
@@ -767,39 +767,47 @@ namespace Newtonsoft.Json.Serialization
contract.InvokeOnDeserializing(list, Serializer.Context);
int initialDepth = reader.Depth;
+ int index = 0;
JsonContract collectionItemContract = GetContractSafe(contract.CollectionItemType);
JsonConverter collectionItemConverter = GetConverter(collectionItemContract, null);
- while (ReadForType(reader, collectionItemContract, collectionItemConverter != null, true))
+ while (true)
{
- switch (reader.TokenType)
+ try
{
- case JsonToken.EndArray:
- contract.InvokeOnDeserialized(list, Serializer.Context);
-
- return wrappedList.UnderlyingCollection;
- case JsonToken.Comment:
- break;
- default:
- try
+ if (ReadForType(reader, collectionItemContract, collectionItemConverter != null, true))
+ {
+ switch (reader.TokenType)
{
- object value = CreateValueNonProperty(reader, contract.CollectionItemType, collectionItemContract, collectionItemConverter);
+ case JsonToken.EndArray:
+ contract.InvokeOnDeserialized(list, Serializer.Context);
- wrappedList.Add(value);
- }
- catch (Exception ex)
- {
- if (IsErrorHandled(list, contract, wrappedList.Count, ex))
- {
- HandleError(reader, initialDepth);
- }
- else
- {
- throw;
- }
+ return wrappedList.UnderlyingCollection;
+ case JsonToken.Comment:
+ break;
+ default:
+ object value = CreateValueNonProperty(reader, contract.CollectionItemType, collectionItemContract, collectionItemConverter);
+
+ wrappedList.Add(value);
+ break;
}
+ }
+ else
+ {
break;
+ }
+ }
+ catch (Exception ex)
+ {
+ if (IsErrorHandled(list, contract, index, reader.Path, ex))
+ HandleError(reader, initialDepth);
+ else
+ throw;
+ }
+ finally
+ {
+ index++;
}
}
@@ -911,7 +919,7 @@ namespace Newtonsoft.Json.Serialization
}
catch (Exception ex)
{
- if (IsErrorHandled(newObject, contract, memberName, ex))
+ if (IsErrorHandled(newObject, contract, memberName, reader.Path, ex))
HandleError(reader, initialDepth);
else
throw;
@@ -1155,71 +1163,88 @@ namespace Newtonsoft.Json.Serialization
switch (reader.TokenType)
{
case JsonToken.PropertyName:
- string memberName = reader.Value.ToString();
-
- try
{
- // attempt exact case match first
- // then try match ignoring case
- JsonProperty property = contract.Properties.GetClosestMatchProperty(memberName);
+ string memberName = reader.Value.ToString();
- if (property == null)
+ try
{
- if (Serializer.MissingMemberHandling == MissingMemberHandling.Error)
- throw CreateSerializationException(reader, "Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType.Name));
+ // attempt exact case match first
+ // then try match ignoring case
+ JsonProperty property = contract.Properties.GetClosestMatchProperty(memberName);
- reader.Skip();
- continue;
- }
+ if (property == null)
+ {
+ if (Serializer.MissingMemberHandling == MissingMemberHandling.Error)
+ throw CreateSerializationException(reader, "Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType.Name));
- if (property.PropertyContract == null)
- property.PropertyContract = GetContractSafe(property.PropertyType);
+ reader.Skip();
+ continue;
+ }
- JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.MemberConverter);
+ if (property.PropertyContract == null)
+ property.PropertyContract = GetContractSafe(property.PropertyType);
- if (!ReadForType(reader, property.PropertyContract, propertyConverter != null, false))
- throw CreateSerializationException(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
+ JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.MemberConverter);
- SetPropertyPresence(reader, property, propertiesPresence);
+ if (!ReadForType(reader, property.PropertyContract, propertyConverter != null, false))
+ throw CreateSerializationException(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
- SetPropertyValue(property, propertyConverter, reader, newObject);
- }
- catch (Exception ex)
- {
- if (IsErrorHandled(newObject, contract, memberName, ex))
- HandleError(reader, initialDepth);
- else
- throw;
+ SetPropertyPresence(reader, property, propertiesPresence);
+
+ SetPropertyValue(property, propertyConverter, reader, newObject);
+ }
+ catch (Exception ex)
+ {
+ if (IsErrorHandled(newObject, contract, memberName, reader.Path, ex))
+ HandleError(reader, initialDepth);
+ else
+ throw;
+ }
}
break;
case JsonToken.EndObject:
- foreach (KeyValuePair<JsonProperty, PropertyPresence> propertyPresence in propertiesPresence)
{
- JsonProperty property = propertyPresence.Key;
- PropertyPresence presence = propertyPresence.Value;
-
- switch (presence)
+ foreach (KeyValuePair<JsonProperty, PropertyPresence> propertyPresence in propertiesPresence)
{
- case PropertyPresence.None:
- if (property.Required == Required.AllowNull || property.Required == Required.Always)
- throw CreateSerializationException(reader, "Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName));
-
- if (property.PropertyContract == null)
- property.PropertyContract = GetContractSafe(property.PropertyType);
-
- if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling), DefaultValueHandling.Populate)
- && property.Writable)
- property.ValueProvider.SetValue(newObject, EnsureType(reader, property.DefaultValue, CultureInfo.InvariantCulture, property.PropertyContract, property.PropertyType));
- break;
- case PropertyPresence.Null:
- if (property.Required == Required.Always)
- throw CreateSerializationException(reader, "Required property '{0}' expects a value but got null.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName));
- break;
+ JsonProperty property = propertyPresence.Key;
+ PropertyPresence presence = propertyPresence.Value;
+
+ if (presence == PropertyPresence.None || presence == PropertyPresence.Null)
+ {
+ try
+ {
+ switch (presence)
+ {
+ case PropertyPresence.None:
+ if (property.Required == Required.AllowNull || property.Required == Required.Always)
+ throw CreateSerializationException(reader, "Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName));
+
+ if (property.PropertyContract == null)
+ property.PropertyContract = GetContractSafe(property.PropertyType);
+
+ if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling), DefaultValueHandling.Populate)
+ && property.Writable)
+ property.ValueProvider.SetValue(newObject, EnsureType(reader, property.DefaultValue, CultureInfo.InvariantCulture, property.PropertyContract, property.PropertyType));
+ break;
+ case PropertyPresence.Null:
+ if (property.Required == Required.Always)
+ throw CreateSerializationException(reader, "Required property '{0}' expects a value but got null.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName));
+ break;
+ }
+ }
+ catch (Exception ex)
+ {
+ if (IsErrorHandled(newObject, contract, property.PropertyName, reader.Path, ex))
+ HandleError(reader, initialDepth);
+ else
+ throw;
+ }
+ }
}
- }
- contract.InvokeOnDeserialized(newObject, Serializer.Context);
- return newObject;
+ contract.InvokeOnDeserialized(newObject, Serializer.Context);
+ return newObject;
+ }
case JsonToken.Comment:
// ignore
break;
diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs
index a77f83c..30341ef 100644
--- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs
+++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs
@@ -330,7 +330,7 @@ namespace Newtonsoft.Json.Serialization
}
catch (Exception ex)
{
- if (IsErrorHandled(value, contract, property.PropertyName, ex))
+ if (IsErrorHandled(value, contract, property.PropertyName, writer.ContainerPath, ex))
HandleError(writer, initialDepth);
else
throw;
@@ -439,7 +439,7 @@ namespace Newtonsoft.Json.Serialization
}
catch (Exception ex)
{
- if (IsErrorHandled(values.UnderlyingCollection, contract, index, ex))
+ if (IsErrorHandled(values.UnderlyingCollection, contract, index, writer.ContainerPath, ex))
HandleError(writer, initialDepth);
else
throw;
@@ -614,7 +614,7 @@ namespace Newtonsoft.Json.Serialization
}
catch (Exception ex)
{
- if (IsErrorHandled(values.UnderlyingDictionary, contract, propertyName, ex))
+ if (IsErrorHandled(values.UnderlyingDictionary, contract, propertyName, writer.ContainerPath, ex))
HandleError(writer, initialDepth);
else
throw;