diff --git a/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs b/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs
index e7b59df5..2b4ef3b3 100644
--- a/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs
+++ b/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs
@@ -241,7 +241,7 @@ now brown cow?", '"', true);
}
[Test]
- [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "After parsing a value an unexpected character was encoutered: t")]
+ [ExpectedException(typeof(JsonReaderException), ExpectedMessage = "After parsing a value an unexpected character was encoutered: t. Line 1, position 20.")]
public void TestInvalidStrings()
{
string orig = @"this is a string ""that has quotes"" ";
diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs
index da144e71..aac7f58f 100644
--- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs
+++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTest.cs
@@ -29,6 +29,7 @@ using System.Text;
using NUnit.Framework;
using Newtonsoft.Json;
using System.IO;
+using System.Xml;
namespace Newtonsoft.Json.Tests
{
@@ -80,43 +81,63 @@ namespace Newtonsoft.Json.Tests
StringReader sr = new StringReader(input);
- using (JsonReader jsonReader = new JsonTextReader(sr))
+ using (JsonTextReader jsonReader = new JsonTextReader(sr))
{
Assert.AreEqual(jsonReader.TokenType, JsonToken.None);
+ Assert.AreEqual(0, jsonReader.LineNumber);
+ Assert.AreEqual(0, jsonReader.LinePosition);
jsonReader.Read();
Assert.AreEqual(jsonReader.TokenType, JsonToken.StartObject);
+ Assert.AreEqual(1, jsonReader.LineNumber);
+ Assert.AreEqual(1, jsonReader.LinePosition);
jsonReader.Read();
Assert.AreEqual(jsonReader.TokenType, JsonToken.PropertyName);
Assert.AreEqual(jsonReader.Value, "CPU");
+ Assert.AreEqual(2, jsonReader.LineNumber);
+ Assert.AreEqual(6, jsonReader.LinePosition);
jsonReader.Read();
Assert.AreEqual(jsonReader.TokenType, JsonToken.String);
Assert.AreEqual(jsonReader.Value, "Intel");
+ Assert.AreEqual(2, jsonReader.LineNumber);
+ Assert.AreEqual(14, jsonReader.LinePosition);
jsonReader.Read();
Assert.AreEqual(jsonReader.TokenType, JsonToken.PropertyName);
Assert.AreEqual(jsonReader.Value, "Drives");
+ Assert.AreEqual(3, jsonReader.LineNumber);
+ Assert.AreEqual(9, jsonReader.LinePosition);
jsonReader.Read();
Assert.AreEqual(jsonReader.TokenType, JsonToken.StartArray);
+ Assert.AreEqual(3, jsonReader.LineNumber);
+ Assert.AreEqual(11, jsonReader.LinePosition);
jsonReader.Read();
Assert.AreEqual(jsonReader.TokenType, JsonToken.String);
Assert.AreEqual(jsonReader.Value, "DVD read/writer");
Assert.AreEqual(jsonReader.QuoteChar, '\'');
+ Assert.AreEqual(4, jsonReader.LineNumber);
+ Assert.AreEqual(21, jsonReader.LinePosition);
jsonReader.Read();
Assert.AreEqual(jsonReader.TokenType, JsonToken.String);
Assert.AreEqual(jsonReader.Value, "500 gigabyte hard drive");
Assert.AreEqual(jsonReader.QuoteChar, '"');
+ Assert.AreEqual(5, jsonReader.LineNumber);
+ Assert.AreEqual(29, jsonReader.LinePosition);
jsonReader.Read();
Assert.AreEqual(jsonReader.TokenType, JsonToken.EndArray);
+ Assert.AreEqual(6, jsonReader.LineNumber);
+ Assert.AreEqual(3, jsonReader.LinePosition);
jsonReader.Read();
Assert.AreEqual(jsonReader.TokenType, JsonToken.EndObject);
+ Assert.AreEqual(7, jsonReader.LineNumber);
+ Assert.AreEqual(1, jsonReader.LinePosition);
}
}
diff --git a/Src/Newtonsoft.Json.Tests/JsonTokenReaderTest.cs b/Src/Newtonsoft.Json.Tests/JsonTokenReaderTest.cs
index efb61485..b9004b9f 100644
--- a/Src/Newtonsoft.Json.Tests/JsonTokenReaderTest.cs
+++ b/Src/Newtonsoft.Json.Tests/JsonTokenReaderTest.cs
@@ -46,18 +46,25 @@ namespace Newtonsoft.Json.Tests
new JProperty("Test4", null)
);
- using (JsonReader jsonReader = new JsonTokenReader(o))
+ using (JsonTokenReader jsonReader = new JsonTokenReader(o))
{
+ IJsonLineInfo lineInfo = jsonReader;
+
jsonReader.Read();
Assert.AreEqual(JsonToken.StartObject, jsonReader.TokenType);
+ Assert.AreEqual(false, lineInfo.HasLineInfo());
jsonReader.Read();
Assert.AreEqual(JsonToken.PropertyName, jsonReader.TokenType);
Assert.AreEqual("Test1", jsonReader.Value);
+ Assert.AreEqual(false, lineInfo.HasLineInfo());
jsonReader.Read();
Assert.AreEqual(JsonToken.Date, jsonReader.TokenType);
Assert.AreEqual(new DateTime(2000, 10, 15, 5, 5, 5, DateTimeKind.Utc), jsonReader.Value);
+ Assert.AreEqual(false, lineInfo.HasLineInfo());
+ Assert.AreEqual(0, lineInfo.LinePosition);
+ Assert.AreEqual(0, lineInfo.LineNumber);
jsonReader.Read();
Assert.AreEqual(JsonToken.PropertyName, jsonReader.TokenType);
@@ -104,7 +111,7 @@ namespace Newtonsoft.Json.Tests
}
[Test]
- public void ReadingIndented()
+ public void ReadLineInfo()
{
string input = @"{
CPU: 'Intel',
@@ -116,140 +123,76 @@ namespace Newtonsoft.Json.Tests
StringReader sr = new StringReader(input);
- using (JsonReader jsonReader = new JsonTextReader(sr))
+ JObject o = JObject.Parse(input);
+
+ using (JsonTokenReader jsonReader = new JsonTokenReader(o))
{
+ IJsonLineInfo lineInfo = jsonReader;
+
Assert.AreEqual(jsonReader.TokenType, JsonToken.None);
+ Assert.AreEqual(0, lineInfo.LineNumber);
+ Assert.AreEqual(0, lineInfo.LinePosition);
+ Assert.AreEqual(false, lineInfo.HasLineInfo());
jsonReader.Read();
Assert.AreEqual(jsonReader.TokenType, JsonToken.StartObject);
+ Assert.AreEqual(1, lineInfo.LineNumber);
+ Assert.AreEqual(1, lineInfo.LinePosition);
+ Assert.AreEqual(true, lineInfo.HasLineInfo());
jsonReader.Read();
Assert.AreEqual(jsonReader.TokenType, JsonToken.PropertyName);
Assert.AreEqual(jsonReader.Value, "CPU");
+ Assert.AreEqual(2, lineInfo.LineNumber);
+ Assert.AreEqual(6, lineInfo.LinePosition);
+ Assert.AreEqual(true, lineInfo.HasLineInfo());
jsonReader.Read();
Assert.AreEqual(jsonReader.TokenType, JsonToken.String);
Assert.AreEqual(jsonReader.Value, "Intel");
+ Assert.AreEqual(2, lineInfo.LineNumber);
+ Assert.AreEqual(14, lineInfo.LinePosition);
+ Assert.AreEqual(true, lineInfo.HasLineInfo());
jsonReader.Read();
Assert.AreEqual(jsonReader.TokenType, JsonToken.PropertyName);
Assert.AreEqual(jsonReader.Value, "Drives");
+ Assert.AreEqual(3, lineInfo.LineNumber);
+ Assert.AreEqual(9, lineInfo.LinePosition);
+ Assert.AreEqual(true, lineInfo.HasLineInfo());
jsonReader.Read();
Assert.AreEqual(jsonReader.TokenType, JsonToken.StartArray);
+ Assert.AreEqual(3, lineInfo.LineNumber);
+ Assert.AreEqual(11, lineInfo.LinePosition);
+ Assert.AreEqual(true, lineInfo.HasLineInfo());
jsonReader.Read();
Assert.AreEqual(jsonReader.TokenType, JsonToken.String);
Assert.AreEqual(jsonReader.Value, "DVD read/writer");
- Assert.AreEqual(jsonReader.QuoteChar, '\'');
+ Assert.AreEqual(4, lineInfo.LineNumber);
+ Assert.AreEqual(21, lineInfo.LinePosition);
+ Assert.AreEqual(true, lineInfo.HasLineInfo());
jsonReader.Read();
Assert.AreEqual(jsonReader.TokenType, JsonToken.String);
Assert.AreEqual(jsonReader.Value, "500 gigabyte hard drive");
- Assert.AreEqual(jsonReader.QuoteChar, '"');
+ Assert.AreEqual(5, lineInfo.LineNumber);
+ Assert.AreEqual(29, lineInfo.LinePosition);
+ Assert.AreEqual(true, lineInfo.HasLineInfo());
jsonReader.Read();
Assert.AreEqual(jsonReader.TokenType, JsonToken.EndArray);
+ Assert.AreEqual(0, lineInfo.LineNumber);
+ Assert.AreEqual(0, lineInfo.LinePosition);
+ Assert.AreEqual(false, lineInfo.HasLineInfo());
jsonReader.Read();
Assert.AreEqual(jsonReader.TokenType, JsonToken.EndObject);
+ Assert.AreEqual(0, lineInfo.LineNumber);
+ Assert.AreEqual(0, lineInfo.LinePosition);
+ Assert.AreEqual(false, lineInfo.HasLineInfo());
}
}
-
- [Test]
- public void ReadingEscapedStrings()
- {
- string input = "{value:'Purple\\r \\n monkey\\'s:\\tdishwasher'}";
-
- StringReader sr = new StringReader(input);
-
- using (JsonReader jsonReader = new JsonTextReader(sr))
- {
- jsonReader.Read();
- Assert.AreEqual(jsonReader.TokenType, JsonToken.StartObject);
-
- jsonReader.Read();
- Assert.AreEqual(jsonReader.TokenType, JsonToken.PropertyName);
-
- jsonReader.Read();
- Assert.AreEqual(jsonReader.TokenType, JsonToken.String);
- Assert.AreEqual(jsonReader.Value, "Purple\r \n monkey's:\tdishwasher");
- Assert.AreEqual(jsonReader.QuoteChar, '\'');
-
- jsonReader.Read();
- Assert.AreEqual(jsonReader.TokenType, JsonToken.EndObject);
- }
- }
-
- [Test]
- public void ReadNewlineLastCharacter()
- {
- string input = @"{
- CPU: 'Intel',
- Drives: [
- 'DVD read/writer',
- ""500 gigabyte hard drive""
- ]
-}" + '\n';
-
- object o = JsonConvert.DeserializeObject(input);
- }
-
- [Test]
- public void WriteReadWrite()
- {
- StringBuilder sb = new StringBuilder();
- StringWriter sw = new StringWriter(sb);
-
- using (JsonWriter jsonWriter = new JsonTextWriter(sw))
- {
- jsonWriter.WriteStartArray();
- jsonWriter.WriteValue(true);
-
- jsonWriter.WriteStartObject();
- jsonWriter.WritePropertyName("integer");
- jsonWriter.WriteValue(99);
- jsonWriter.WritePropertyName("string");
- jsonWriter.WriteValue("how now brown cow?");
- jsonWriter.WritePropertyName("array");
-
- jsonWriter.WriteStartArray();
- for (int i = 0; i < 5; i++)
- {
- jsonWriter.WriteValue(i);
- }
-
- jsonWriter.WriteStartObject();
- jsonWriter.WritePropertyName("decimal");
- jsonWriter.WriteValue(990.00990099m);
- jsonWriter.WriteEndObject();
-
- jsonWriter.WriteValue(5);
- jsonWriter.WriteEndArray();
-
- jsonWriter.WriteEndObject();
-
- jsonWriter.WriteValue("This is a string.");
- jsonWriter.WriteNull();
- jsonWriter.WriteNull();
- jsonWriter.WriteEndArray();
- }
-
- string json = sb.ToString();
-
- JsonSerializer serializer = new JsonSerializer();
-
- object jsonObject = serializer.Deserialize(new JsonTextReader(new StringReader(json)));
-
- sb = new StringBuilder();
- sw = new StringWriter(sb);
-
- using (JsonWriter jsonWriter = new JsonTextWriter(sw))
- {
- serializer.Serialize(sw, jsonObject);
- }
-
- Assert.AreEqual(json, sb.ToString());
- }
}
}
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json.Tests/JsonValidatingReaderTests.cs b/Src/Newtonsoft.Json.Tests/JsonValidatingReaderTests.cs
index c757c352..31a484b5 100644
--- a/Src/Newtonsoft.Json.Tests/JsonValidatingReaderTests.cs
+++ b/Src/Newtonsoft.Json.Tests/JsonValidatingReaderTests.cs
@@ -184,7 +184,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.String, reader.TokenType);
- Assert.AreEqual("String 'pie' is less than minimum length of 5.", validationEventArgs.Message);
+ Assert.AreEqual("String 'pie' is less than minimum length of 5. Line 1, position 5.", validationEventArgs.Message);
Assert.IsNotNull(validationEventArgs);
}
@@ -208,7 +208,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.String, reader.TokenType);
- Assert.AreEqual("String 'The quick brown fox jumps over the lazy dog.' exceeds maximum length of 10.", validationEventArgs.Message);
+ Assert.AreEqual("String 'The quick brown fox jumps over the lazy dog.' exceeds maximum length of 10. Line 1, position 46.", validationEventArgs.Message);
Assert.IsNotNull(validationEventArgs);
}
@@ -245,7 +245,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.String, reader.TokenType);
- Assert.AreEqual(@"Value ""THREE"" is not defined in enum.", validationEventArgs.Message);
+ Assert.AreEqual(@"Value ""THREE"" is not defined in enum. Line 1, position 20.", validationEventArgs.Message);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
@@ -271,7 +271,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.String, reader.TokenType);
- Assert.AreEqual("String 'The quick brown fox jumps over the lazy dog.' does not match regex pattern 'foo'.", validationEventArgs.Message);
+ Assert.AreEqual("String 'The quick brown fox jumps over the lazy dog.' does not match regex pattern 'foo'. Line 1, position 46.", validationEventArgs.Message);
Assert.IsNotNull(validationEventArgs);
}
@@ -294,13 +294,13 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.Integer, reader.TokenType);
- Assert.AreEqual("Integer 10 exceeds maximum value of 5.", validationEventArgs.Message);
+ Assert.AreEqual("Integer 10 exceeds maximum value of 5. Line 1, position 2.", validationEventArgs.Message);
Assert.IsNotNull(validationEventArgs);
}
[Test]
- [ExpectedException(typeof(JsonSchemaException), ExpectedMessage = "Integer 10 exceeds maximum value of 5.")]
+ [ExpectedException(typeof(JsonSchemaException), ExpectedMessage = "Integer 10 exceeds maximum value of 5. Line 1, position 2.")]
public void ThrowExceptionWhenNoValidationEventHandler()
{
string schemaJson = @"{
@@ -332,7 +332,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.Integer, reader.TokenType);
- Assert.AreEqual("Integer 1 is less than minimum value of 5.", validationEventArgs.Message);
+ Assert.AreEqual("Integer 1 is less than minimum value of 5. Line 1, position 1.", validationEventArgs.Message);
Assert.IsNotNull(validationEventArgs);
}
@@ -369,7 +369,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.Integer, reader.TokenType);
- Assert.AreEqual(@"Value 3 is not defined in enum.", validationEventArgs.Message);
+ Assert.AreEqual(@"Value 3 is not defined in enum. Line 1, position 7.", validationEventArgs.Message);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
@@ -395,7 +395,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.Float, reader.TokenType);
- Assert.AreEqual("Float 10.0 exceeds maximum value of 5.", validationEventArgs.Message);
+ Assert.AreEqual("Float 10.0 exceeds maximum value of 5. Line 1, position 4.", validationEventArgs.Message);
Assert.IsNotNull(validationEventArgs);
}
@@ -418,7 +418,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.Float, reader.TokenType);
- Assert.AreEqual("Float 1.1 is less than minimum value of 5.", validationEventArgs.Message);
+ Assert.AreEqual("Float 1.1 is less than minimum value of 5. Line 1, position 3.", validationEventArgs.Message);
Assert.IsNotNull(validationEventArgs);
}
@@ -455,7 +455,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.Float, reader.TokenType);
- Assert.AreEqual(@"Value 3.0 is not defined in enum.", validationEventArgs.Message);
+ Assert.AreEqual(@"Value 3.0 is not defined in enum. Line 1, position 13.", validationEventArgs.Message);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
@@ -494,7 +494,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.Float, reader.TokenType);
- Assert.AreEqual(@"Float 4.001 exceeds the maximum allowed number decimal places of 2.", validationEventArgs.Message);
+ Assert.AreEqual(@"Float 4.001 exceeds the maximum allowed number decimal places of 2. Line 1, position 15.", validationEventArgs.Message);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
@@ -527,7 +527,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.Null, reader.TokenType);
- Assert.AreEqual(@"Value null is not defined in enum.", validationEventArgs.Message);
+ Assert.AreEqual(@"Value null is not defined in enum. Line 1, position 6.", validationEventArgs.Message);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
@@ -564,7 +564,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.Boolean, reader.TokenType);
- Assert.AreEqual(@"Value false is not defined in enum.", validationEventArgs.Message);
+ Assert.AreEqual(@"Value false is not defined in enum. Line 1, position 12.", validationEventArgs.Message);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
@@ -603,7 +603,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
- Assert.AreEqual("Array item count 4 exceeds maximum count of 3.", validationEventArgs.Message);
+ Assert.AreEqual("Array item count 4 exceeds maximum count of 3. Line 1, position 21.", validationEventArgs.Message);
Assert.IsNotNull(validationEventArgs);
}
@@ -633,7 +633,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
- Assert.AreEqual("Array item count 1 is less than minimum count of 2.", validationEventArgs.Message);
+ Assert.AreEqual("Array item count 1 is less than minimum count of 2. Line 1, position 6.", validationEventArgs.Message);
Assert.IsNotNull(validationEventArgs);
}
@@ -658,7 +658,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
- Assert.AreEqual(@"Invalid type. Expected String but got Array.", validationEventArgs.Message);
+ Assert.AreEqual(@"Invalid type. Expected String but got Array. Line 1, position 1.", validationEventArgs.Message);
Assert.IsNotNull(validationEventArgs);
}
@@ -691,7 +691,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.Float, reader.TokenType);
- Assert.AreEqual(@"Type Float is disallowed.", validationEventArgs.Message);
+ Assert.AreEqual(@"Type Float is disallowed. Line 1, position 11.", validationEventArgs.Message);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
@@ -735,7 +735,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
- Assert.AreEqual("Non-optional properties are missing from object: hobbies, age", validationEventArgs.Message);
+ Assert.AreEqual("Non-optional properties are missing from object: hobbies, age. Line 1, position 16.", validationEventArgs.Message);
Assert.IsNotNull(validationEventArgs);
}
@@ -820,7 +820,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.Null, reader.TokenType);
Assert.AreEqual(null, reader.Value);
- Assert.AreEqual("Property 'additionalProperty1' has not been defined and schema does not allow additional properties.", validationEventArgs.Message);
+ Assert.AreEqual("Property 'additionalProperty1' has not been defined and the schema does not allow additional properties. Line 1, position 38.", validationEventArgs.Message);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
@@ -829,7 +829,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.Null, reader.TokenType);
Assert.AreEqual(null, reader.Value);
- Assert.AreEqual("Property 'additionalProperty2' has not been defined and schema does not allow additional properties.", validationEventArgs.Message);
+ Assert.AreEqual("Property 'additionalProperty2' has not been defined and the schema does not allow additional properties. Line 1, position 65.", validationEventArgs.Message);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
@@ -861,7 +861,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.String, reader.TokenType);
Assert.AreEqual(1, errors.Count);
- Assert.AreEqual("String 'The quick brown fox jumps over the lazy dog.' exceeds maximum length of 9.", errors[0]);
+ Assert.AreEqual("String 'The quick brown fox jumps over the lazy dog.' exceeds maximum length of 9. Line 1, position 46.", errors[0]);
Assert.IsNotNull(validationEventArgs);
}
@@ -933,7 +933,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
Assert.AreEqual("additional", reader.Value.ToString());
- Assert.AreEqual("Property 'additional' has not been defined and schema does not allow additional properties.", validationEventArgs.Message);
+ Assert.AreEqual("Property 'additional' has not been defined and the schema does not allow additional properties. Line 1, position 62.", validationEventArgs.Message);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.String, reader.TokenType);
@@ -942,7 +942,7 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
Assert.AreEqual("additional2", reader.Value.ToString());
- Assert.AreEqual("Property 'additional2' has not been defined and schema does not allow additional properties.", validationEventArgs.Message);
+ Assert.AreEqual("Property 'additional2' has not been defined and the schema does not allow additional properties. Line 1, position 84.", validationEventArgs.Message);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.String, reader.TokenType);
@@ -972,7 +972,7 @@ namespace Newtonsoft.Json.Tests
Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
Assert.AreEqual(1, errors.Count);
- Assert.AreEqual("Non-optional properties are missing from object: secondproperty, firstproperty", errors[0]);
+ Assert.AreEqual("Non-optional properties are missing from object: secondproperty, firstproperty. Line 1, position 2.", errors[0]);
}
[Test]
@@ -997,15 +997,15 @@ namespace Newtonsoft.Json.Tests
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.Integer, reader.TokenType);
- Assert.AreEqual("Invalid type. Expected String but got Integer.", validationEventArgs.Message);
+ Assert.AreEqual("Invalid type. Expected String but got Integer. Line 1, position 3.", validationEventArgs.Message);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.String, reader.TokenType);
- Assert.AreEqual("Invalid type. Expected Integer but got String.", validationEventArgs.Message);
+ Assert.AreEqual("Invalid type. Expected Integer but got String. Line 1, position 7.", validationEventArgs.Message);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.Null, reader.TokenType);
- Assert.AreEqual("Index 3 has not been defined and schema does not allow additional items.", validationEventArgs.Message);
+ Assert.AreEqual("Index 3 has not been defined and the schema does not allow additional items. Line 1, position 14.", validationEventArgs.Message);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
@@ -1103,7 +1103,7 @@ namespace Newtonsoft.Json.Tests
Assert.AreEqual(JsonToken.String, reader.TokenType);
Assert.AreEqual("secasecasecasecaseca", reader.Value.ToString());
Assert.AreEqual(1, errors.Count);
- Assert.AreEqual("String 'secasecasecasecaseca' exceeds maximum length of 10.", errors[0]);
+ Assert.AreEqual("String 'secasecasecasecaseca' exceeds maximum length of 10. Line 3, position 41.", errors[0]);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
@@ -1123,9 +1123,9 @@ namespace Newtonsoft.Json.Tests
Assert.AreEqual(JsonToken.String, reader.TokenType);
Assert.AreEqual("aaa", reader.Value.ToString());
Assert.AreEqual(4, errors.Count);
- Assert.AreEqual("String 'aaa' is less than minimum length of 7.", errors[1]);
- Assert.AreEqual("String 'aaa' does not match regex pattern 'hi'.", errors[2]);
- Assert.AreEqual("String 'aaa' does not match regex pattern 'hi2u'.", errors[3]);
+ Assert.AreEqual("String 'aaa' is less than minimum length of 7. Line 5, position 39.", errors[1]);
+ Assert.AreEqual("String 'aaa' does not match regex pattern 'hi'. Line 5, position 39.", errors[2]);
+ Assert.AreEqual("String 'aaa' does not match regex pattern 'hi2u'. Line 5, position 39.", errors[3]);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
@@ -1136,7 +1136,7 @@ namespace Newtonsoft.Json.Tests
Assert.AreEqual(JsonToken.String, reader.TokenType);
Assert.AreEqual("three", reader.Value.ToString());
Assert.AreEqual(5, errors.Count);
- Assert.AreEqual("String 'three' is less than minimum length of 6.", errors[4]);
+ Assert.AreEqual("String 'three' is less than minimum length of 6. Line 6, position 24.", errors[4]);
Assert.IsTrue(reader.Read());
Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
index 602c090a..fd527a54 100644
--- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
+++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj
@@ -67,6 +67,7 @@
3.5
+
3.5
diff --git a/Src/Newtonsoft.Json.Tests/Schema/ExtensionsTests.cs b/Src/Newtonsoft.Json.Tests/Schema/ExtensionsTests.cs
index bad8accd..1eb0961e 100644
--- a/Src/Newtonsoft.Json.Tests/Schema/ExtensionsTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Schema/ExtensionsTests.cs
@@ -80,5 +80,31 @@ namespace Newtonsoft.Json.Tests.Schema
JToken stringToken = JToken.FromObject("pie lol");
stringToken.Validate(schema);
}
+
+ [Test]
+ public void ValidateFailureWithOutLineInfoBecauseOfEndToken()
+ {
+ JsonSchema schema = JsonSchema.Parse("{'properties':{'lol':{}}}");
+ JObject o = JObject.Parse("{}");
+
+ List errors = new List();
+ o.Validate(schema, (sender, args) => errors.Add(args.Message));
+
+ Assert.AreEqual("Non-optional properties are missing from object: lol.", errors[0]);
+ Assert.AreEqual(1, errors.Count);
+ }
+
+ [Test]
+ public void ValidateFailureWithLineInfo()
+ {
+ JsonSchema schema = JsonSchema.Parse("{'properties':{'lol':{'type':'string'}}}");
+ JObject o = JObject.Parse("{'lol':1}");
+
+ List errors = new List();
+ o.Validate(schema, (sender, args) => errors.Add(args.Message));
+
+ Assert.AreEqual("Invalid type. Expected String but got Integer. Line 1, position 9.", errors[0]);
+ Assert.AreEqual(1, errors.Count);
+ }
}
}
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaGeneratorTests.cs b/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaGeneratorTests.cs
index 7b34c5fd..3c6bcb7a 100644
--- a/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaGeneratorTests.cs
+++ b/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaGeneratorTests.cs
@@ -24,11 +24,18 @@
#endregion
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Globalization;
+using Newtonsoft.Json.Converters;
+using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Tests.TestObjects;
+using Newtonsoft.Json.Utilities;
using NUnit.Framework;
using Newtonsoft.Json.Schema;
+using System.IO;
+using System.Linq;
+using Newtonsoft.Json.Linq;
namespace Newtonsoft.Json.Tests.Schema
{
@@ -65,6 +72,7 @@ namespace Newtonsoft.Json.Tests.Schema
Assert.AreEqual(@"{
""description"": ""DefaultValueAttributeTestClass description!"",
""type"": ""object"",
+ ""additionalProperties"": false,
""properties"": {
""TestField1"": {
""type"": ""integer"",
@@ -261,5 +269,113 @@ namespace Newtonsoft.Json.Tests.Schema
Assert.AreEqual(JsonSchemaType.Object, schema.Properties["Child"].Type);
Assert.AreEqual(schema, schema.Properties["Child"]);
}
+
+ [Test]
+ public void GenerateSchemaForType()
+ {
+ JsonSchemaGenerator generator = new JsonSchemaGenerator();
+ generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
+
+ JsonSchema schema = generator.Generate(typeof(Type));
+
+ Assert.AreEqual(JsonSchemaType.String, schema.Type);
+ }
+
+ public class CustomDirectoryInfoSerializer : JsonSerializer
+ {
+ protected override Newtonsoft.Json.Serialization.JsonMemberMappingCollection GetMemberMappings(Type objectType)
+ {
+ JsonMemberMappingCollection mappings = base.GetMemberMappings(objectType);
+
+ JsonMemberMappingCollection c = new JsonMemberMappingCollection();
+ CollectionUtils.AddRange(c, (IEnumerable) mappings.Where(m => m.MappingName != "Root"));
+
+ return c;
+ }
+ }
+
+ [Test]
+ public void GenerateSchemaForDirectoryInfo()
+ {
+ JsonSchemaGenerator generator = new JsonSchemaGenerator();
+ generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName;
+
+ JsonSchema schema = generator.Generate(typeof(DirectoryInfo), true);
+
+ string json = schema.ToString();
+
+ Assert.AreEqual(@"{
+ ""id"": ""System.IO.DirectoryInfo"",
+ ""type"": [
+ ""object"",
+ ""null""
+ ],
+ ""additionalProperties"": false,
+ ""properties"": {
+ ""Name"": {
+ ""type"": [
+ ""string"",
+ ""null""
+ ]
+ },
+ ""Parent"": {
+ ""$ref"": ""System.IO.DirectoryInfo""
+ },
+ ""Exists"": {
+ ""type"": ""boolean""
+ },
+ ""Root"": {
+ ""$ref"": ""System.IO.DirectoryInfo""
+ },
+ ""FullName"": {
+ ""type"": [
+ ""string"",
+ ""null""
+ ]
+ },
+ ""Extension"": {
+ ""type"": [
+ ""string"",
+ ""null""
+ ]
+ },
+ ""CreationTime"": {
+ ""type"": ""string""
+ },
+ ""CreationTimeUtc"": {
+ ""type"": ""string""
+ },
+ ""LastAccessTime"": {
+ ""type"": ""string""
+ },
+ ""LastAccessTimeUtc"": {
+ ""type"": ""string""
+ },
+ ""LastWriteTime"": {
+ ""type"": ""string""
+ },
+ ""LastWriteTimeUtc"": {
+ ""type"": ""string""
+ },
+ ""Attributes"": {
+ ""type"": ""integer""
+ }
+ }
+}", json);
+
+ DirectoryInfo temp = new DirectoryInfo(@"c:\temp");
+
+ JsonTokenWriter jsonWriter = new JsonTokenWriter();
+ CustomDirectoryInfoSerializer customSerializer = new CustomDirectoryInfoSerializer();
+ customSerializer.Converters.Add(new IsoDateTimeConverter());
+ customSerializer.Serialize(jsonWriter, temp);
+
+ List errors = new List();
+ jsonWriter.Token.Validate(schema, (sender, args) => errors.Add(args.Message));
+
+ Assert.AreEqual(2, errors.Count);
+ Assert.AreEqual("Non-optional properties are missing from object: Root.", errors[0]);
+ Assert.AreEqual("Non-optional properties are missing from object: Root.", errors[1]);
+ }
}
}
diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/DefaultValueAttributeTestClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/DefaultValueAttributeTestClass.cs
index 861c709a..eeefa5e3 100644
--- a/Src/Newtonsoft.Json.Tests/TestObjects/DefaultValueAttributeTestClass.cs
+++ b/Src/Newtonsoft.Json.Tests/TestObjects/DefaultValueAttributeTestClass.cs
@@ -30,7 +30,7 @@ namespace Newtonsoft.Json.Tests.TestObjects
#if !PocketPC
[Description("DefaultValueAttributeTestClass description!")]
#endif
- public class DefaultValueAttributeTestClass
+ public sealed class DefaultValueAttributeTestClass
{
[DefaultValue("TestProperty1Value")]
public string TestProperty1 { get; set; }
diff --git a/Src/Newtonsoft.Json/IJsonLineInfo.cs b/Src/Newtonsoft.Json/IJsonLineInfo.cs
new file mode 100644
index 00000000..6c821adb
--- /dev/null
+++ b/Src/Newtonsoft.Json/IJsonLineInfo.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Newtonsoft.Json
+{
+ public interface IJsonLineInfo
+ {
+ bool HasLineInfo();
+
+ int LineNumber { get; }
+ int LinePosition { get; }
+ }
+}
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/JsonReaderException.cs b/Src/Newtonsoft.Json/JsonReaderException.cs
index 9940c670..3d6efe44 100644
--- a/Src/Newtonsoft.Json/JsonReaderException.cs
+++ b/Src/Newtonsoft.Json/JsonReaderException.cs
@@ -34,6 +34,9 @@ namespace Newtonsoft.Json
///
public class JsonReaderException : Exception
{
+ public int LineNumber { get; private set; }
+ public int LinePosition { get; private set; }
+
///
/// Initializes a new instance of the class.
///
@@ -61,5 +64,12 @@ namespace Newtonsoft.Json
: base(message, innerException)
{
}
+
+ internal JsonReaderException(string message, Exception innerException, int lineNumber, int linePosition)
+ : base(message, innerException)
+ {
+ LineNumber = lineNumber;
+ LinePosition = linePosition;
+ }
}
}
diff --git a/Src/Newtonsoft.Json/JsonTextReader.cs b/Src/Newtonsoft.Json/JsonTextReader.cs
index db67b261..6cd83fb2 100644
--- a/Src/Newtonsoft.Json/JsonTextReader.cs
+++ b/Src/Newtonsoft.Json/JsonTextReader.cs
@@ -29,19 +29,21 @@ using System.Text;
using System.IO;
using System.Xml;
using System.Globalization;
+using Newtonsoft.Json.Utilities;
namespace Newtonsoft.Json
{
///
/// Represents a reader that provides fast, non-cached, forward-only access to serialized Json data.
///
- public class JsonTextReader : JsonReader
+ public class JsonTextReader : JsonReader, IJsonLineInfo
{
- private TextReader _reader;
+ private readonly TextReader _reader;
+ private readonly StringBuffer _buffer;
private char _currentChar;
-
- // current Token data
- private StringBuffer _buffer;
+ private int _currentLinePosition;
+ private int _currentLineNumber;
+ private bool _currentCharCarriageReturn;
///
/// Initializes a new instance of the class with the specified .
@@ -54,6 +56,7 @@ namespace Newtonsoft.Json
_reader = reader;
_buffer = new StringBuffer(4096);
+ _currentLineNumber = 1;
}
private void ParseString(char quote)
@@ -100,7 +103,7 @@ namespace Newtonsoft.Json
}
else
{
- throw new JsonReaderException("Unterminated string. Expected delimiter: " + quote);
+ throw CreateJsonReaderException("Unterminated string. Expected delimiter: {0}. Line {1}, position {2}.", quote, _currentLineNumber, _currentLinePosition);
}
break;
case '"':
@@ -130,7 +133,7 @@ namespace Newtonsoft.Json
}
if (!stringTerminated)
- throw new JsonReaderException("Unterminated string. Expected delimiter: " + quote);
+ throw CreateJsonReaderException("Unterminated string. Expected delimiter: {0}. Line {1}, position {2}.", quote, _currentLineNumber, _currentLinePosition);
ClearCurrentChar();
string text = _buffer.ToString();
@@ -147,6 +150,12 @@ namespace Newtonsoft.Json
}
}
+ private JsonReaderException CreateJsonReaderException(string format, params object[] args)
+ {
+ string message = format.FormatWith(CultureInfo.InvariantCulture, args);
+ return new JsonReaderException(message, null, _currentLineNumber, _currentLinePosition);
+ }
+
///
/// Sets the current token and value.
///
@@ -218,20 +227,37 @@ namespace Newtonsoft.Json
SetToken(JsonToken.Date, dateTime);
}
+ private const int LineFeedValue = StringUtils.LineFeed;
+ private const int CarriageReturnValue = StringUtils.CarriageReturn;
+
private bool MoveNext()
{
int value = _reader.Read();
- if (value != -1)
+ switch (value)
{
- _currentChar = (char)value;
- //_testBuffer.Append(_currentChar);
- return true;
- }
- else
- {
- return false;
+ case -1:
+ return false;
+ case CarriageReturnValue:
+ _currentLineNumber++;
+ _currentLinePosition = 0;
+ _currentCharCarriageReturn = true;
+ break;
+ case LineFeedValue:
+ if (!_currentCharCarriageReturn)
+ _currentLineNumber++;
+
+ _currentLinePosition = 0;
+ _currentCharCarriageReturn = false;
+ break;
+ default:
+ _currentLinePosition++;
+ _currentCharCarriageReturn = false;
+ break;
}
+
+ _currentChar = (char)value;
+ return true;
}
private bool HasNext()
@@ -300,7 +326,7 @@ namespace Newtonsoft.Json
case State.Error:
break;
default:
- throw new JsonReaderException("Unexpected state: " + CurrentState);
+ throw CreateJsonReaderException("Unexpected state: {0}. Line {1}, position {2}.", CurrentState, _currentLineNumber, _currentLinePosition);
}
}
}
@@ -339,7 +365,7 @@ namespace Newtonsoft.Json
}
else
{
- throw new JsonReaderException("After parsing a value an unexpected character was encoutered: " + _currentChar);
+ throw CreateJsonReaderException("After parsing a value an unexpected character was encoutered: {0}. Line {1}, position {2}.", _currentChar, _currentLineNumber, _currentLinePosition);
}
break;
}
@@ -395,7 +421,7 @@ namespace Newtonsoft.Json
}
else
{
- throw new JsonReaderException("Invalid property identifier character: " + _currentChar);
+ throw CreateJsonReaderException("Invalid property identifier character: {0}. Line {1}, position {2}.", _currentChar, _currentLineNumber, _currentLinePosition);
}
// finished property. move to colon
@@ -426,7 +452,7 @@ namespace Newtonsoft.Json
}
}
- throw new JsonReaderException("Unclosed quoted property. Expected: " + quoteChar);
+ throw CreateJsonReaderException("Unclosed quoted property. Expected: {0}. Line {1}, position {2}.", quoteChar, _currentLineNumber, _currentLinePosition);
}
private bool ValidIdentifierChar(char value)
@@ -451,7 +477,7 @@ namespace Newtonsoft.Json
}
else
{
- throw new JsonReaderException("Invalid JavaScript property identifier character: " + _currentChar);
+ throw CreateJsonReaderException("Invalid JavaScript property identifier character: {0}. Line {1}, position {2}.", _currentChar, _currentLineNumber, _currentLinePosition);
}
}
}
@@ -482,11 +508,11 @@ namespace Newtonsoft.Json
else if (next == 'e')
ParseConstructor();
else
- throw new JsonReaderException("Unexpected character encountered while parsing value: " + _currentChar);
+ throw CreateJsonReaderException("Unexpected character encountered while parsing value: {0}. Line {1}, position {2}.", _currentChar, _currentLineNumber, _currentLinePosition);
}
else
{
- throw new JsonReaderException("Unexpected end");
+ throw CreateJsonReaderException("Unexpected end. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
}
return true;
case 'N':
@@ -538,7 +564,7 @@ namespace Newtonsoft.Json
}
else
{
- throw new JsonReaderException("Unexpected character encountered while parsing value: " + _currentChar);
+ throw CreateJsonReaderException("Unexpected character encountered while parsing value: {0}. Line {1}, position {2}.", _currentChar, _currentLineNumber, _currentLinePosition);
}
break;
}
@@ -574,7 +600,7 @@ namespace Newtonsoft.Json
EatWhitespace(false);
if (_currentChar != '(')
- throw new JsonReaderException("Unexpected character while parsing constructor: " + _currentChar);
+ throw CreateJsonReaderException("Unexpected character while parsing constructor: {0}. Line {1}, position {2}.", _currentChar, _currentLineNumber, _currentLinePosition);
string constructorName = _buffer.ToString();
_buffer.Position = 0;
@@ -655,7 +681,7 @@ namespace Newtonsoft.Json
}
else
{
- throw new JsonReaderException("Error parsing comment. Expected: *");
+ throw CreateJsonReaderException("Error parsing comment. Expected: *. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
}
SetToken(JsonToken.Comment, _buffer.ToString());
@@ -735,7 +761,7 @@ namespace Newtonsoft.Json
}
else
{
- throw new JsonReaderException("Error parsing boolean value.");
+ throw CreateJsonReaderException("Error parsing boolean value. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
}
}
@@ -747,7 +773,7 @@ namespace Newtonsoft.Json
}
else
{
- throw new JsonReaderException("Error parsing null value.");
+ throw CreateJsonReaderException("Error parsing null value. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
}
}
@@ -759,7 +785,7 @@ namespace Newtonsoft.Json
}
else
{
- throw new JsonReaderException("Error parsing undefined value.");
+ throw CreateJsonReaderException("Error parsing undefined value. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
}
}
@@ -771,7 +797,7 @@ namespace Newtonsoft.Json
}
else
{
- throw new JsonReaderException("Error parsing boolean value.");
+ throw CreateJsonReaderException("Error parsing boolean value. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
}
}
@@ -783,7 +809,7 @@ namespace Newtonsoft.Json
}
else
{
- throw new JsonReaderException("Error parsing negative infinity value.");
+ throw CreateJsonReaderException("Error parsing negative infinity value. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
}
}
@@ -795,7 +821,7 @@ namespace Newtonsoft.Json
}
else
{
- throw new JsonReaderException("Error parsing positive infinity value.");
+ throw CreateJsonReaderException("Error parsing positive infinity value. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
}
}
@@ -807,7 +833,7 @@ namespace Newtonsoft.Json
}
else
{
- throw new JsonReaderException("Error parsing NaN value.");
+ throw CreateJsonReaderException("Error parsing NaN value. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
}
}
@@ -824,5 +850,26 @@ namespace Newtonsoft.Json
if (_buffer != null)
_buffer.Clear();
}
+
+ public bool HasLineInfo()
+ {
+ return true;
+ }
+
+ public int LineNumber
+ {
+ get
+ {
+ if (CurrentState == State.Start)
+ return 0;
+
+ return _currentLineNumber;
+ }
+ }
+
+ public int LinePosition
+ {
+ get { return _currentLinePosition; }
+ }
}
}
diff --git a/Src/Newtonsoft.Json/JsonValidatingReader.cs b/Src/Newtonsoft.Json/JsonValidatingReader.cs
index faa2b62e..d0021689 100644
--- a/Src/Newtonsoft.Json/JsonValidatingReader.cs
+++ b/Src/Newtonsoft.Json/JsonValidatingReader.cs
@@ -35,7 +35,7 @@ using System.Text.RegularExpressions;
namespace Newtonsoft.Json
{
- public class JsonValidatingReader : JsonReader
+ public class JsonValidatingReader : JsonReader, IJsonLineInfo
{
private class SchemaScope
{
@@ -186,7 +186,13 @@ namespace Newtonsoft.Json
private void RaiseError(string message, JsonSchemaModel schema)
{
- OnValidationEvent(new JsonSchemaException(message));
+ IJsonLineInfo lineInfo = this;
+
+ string exceptionMessage = (lineInfo.HasLineInfo())
+ ? message + " Line {0}, position {1}.".FormatWith(CultureInfo.InvariantCulture, lineInfo.LineNumber, lineInfo.LinePosition)
+ : message;
+
+ OnValidationEvent(new JsonSchemaException(exceptionMessage, null, lineInfo.LineNumber, lineInfo.LinePosition));
}
private void OnValidationEvent(JsonSchemaException exception)
@@ -362,7 +368,7 @@ namespace Newtonsoft.Json
requiredProperties.Where(kv => !kv.Value).Select(kv => kv.Key).ToList();
if (unmatchedRequiredProperties.Count > 0)
- RaiseError("Non-optional properties are missing from object: {0}".FormatWith(CultureInfo.InvariantCulture, string.Join(", ", unmatchedRequiredProperties.ToArray())), schema);
+ RaiseError("Non-optional properties are missing from object: {0}.".FormatWith(CultureInfo.InvariantCulture, string.Join(", ", unmatchedRequiredProperties.ToArray())), schema);
}
}
@@ -456,7 +462,7 @@ namespace Newtonsoft.Json
_currentScope.ArrayItemCount++;
if (CurrentSchema != null && CurrentSchema.Items != null && CurrentSchema.Items.Count > 1 && _currentScope.ArrayItemCount >= CurrentSchema.Items.Count)
- RaiseError("Index {0} has not been defined and schema does not allow additional items.".FormatWith(CultureInfo.InvariantCulture, _currentScope.ArrayItemCount), CurrentSchema);
+ RaiseError("Index {0} has not been defined and the schema does not allow additional items.".FormatWith(CultureInfo.InvariantCulture, _currentScope.ArrayItemCount), CurrentSchema);
}
}
@@ -498,7 +504,7 @@ namespace Newtonsoft.Json
if (!schema.AllowAdditionalProperties && !definedProperties.Contains(propertyName))
{
- RaiseError("Property '{0}' has not been defined and schema does not allow additional properties.".FormatWith(CultureInfo.InvariantCulture, propertyName), schema);
+ RaiseError("Property '{0}' has not been defined and the schema does not allow additional properties.".FormatWith(CultureInfo.InvariantCulture, propertyName), schema);
}
}
@@ -531,5 +537,29 @@ namespace Newtonsoft.Json
return true;
}
+
+ bool IJsonLineInfo.HasLineInfo()
+ {
+ IJsonLineInfo lineInfo = _reader as IJsonLineInfo;
+ return (lineInfo != null) ? lineInfo.HasLineInfo() : false;
+ }
+
+ int IJsonLineInfo.LineNumber
+ {
+ get
+ {
+ IJsonLineInfo lineInfo = _reader as IJsonLineInfo;
+ return (lineInfo != null) ? lineInfo.LineNumber : 0;
+ }
+ }
+
+ int IJsonLineInfo.LinePosition
+ {
+ get
+ {
+ IJsonLineInfo lineInfo = _reader as IJsonLineInfo;
+ return (lineInfo != null) ? lineInfo.LinePosition : 0;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Linq/JArray.cs b/Src/Newtonsoft.Json/Linq/JArray.cs
index 5466efe9..6e7426ac 100644
--- a/Src/Newtonsoft.Json/Linq/JArray.cs
+++ b/Src/Newtonsoft.Json/Linq/JArray.cs
@@ -105,15 +105,14 @@ namespace Newtonsoft.Json.Linq
throw new Exception("Error reading JArray from JsonReader.");
}
if (reader.TokenType != JsonToken.StartArray)
- throw new Exception(
- "Error reading JArray from JsonReader. Current JsonReader item is not an array: {0}".FormatWith(
- CultureInfo.InvariantCulture, reader.TokenType));
+ throw new Exception("Error reading JArray from JsonReader. Current JsonReader item is not an array: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
+
+ JArray a = new JArray();
+ a.SetLineInfo(reader as IJsonLineInfo);
if (!reader.Read())
throw new Exception("Error reading JArray from JsonReader.");
-
- JArray a = new JArray();
a.ReadContentFrom(reader);
return a;
diff --git a/Src/Newtonsoft.Json/Linq/JConstructor.cs b/Src/Newtonsoft.Json/Linq/JConstructor.cs
index dba14b85..069048bd 100644
--- a/Src/Newtonsoft.Json/Linq/JConstructor.cs
+++ b/Src/Newtonsoft.Json/Linq/JConstructor.cs
@@ -175,11 +175,10 @@ namespace Newtonsoft.Json.Linq
}
if (reader.TokenType != JsonToken.StartConstructor)
- throw new Exception(
- "Error reading JConstructor from JsonReader. Current JsonReader item is not a constructor: {0}".FormatWith(
- CultureInfo.InvariantCulture, reader.TokenType));
+ throw new Exception("Error reading JConstructor from JsonReader. Current JsonReader item is not a constructor: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
JConstructor c = new JConstructor((string)reader.Value);
+ c.SetLineInfo(reader as IJsonLineInfo);
if (!reader.Read())
throw new Exception("Error reading JConstructor from JsonReader.");
diff --git a/Src/Newtonsoft.Json/Linq/JContainer.cs b/Src/Newtonsoft.Json/Linq/JContainer.cs
index 043c6d98..031fb0b0 100644
--- a/Src/Newtonsoft.Json/Linq/JContainer.cs
+++ b/Src/Newtonsoft.Json/Linq/JContainer.cs
@@ -365,6 +365,7 @@ namespace Newtonsoft.Json.Linq
internal void ReadContentFrom(JsonReader r)
{
ValidationUtils.ArgumentNotNull(r, "r");
+ IJsonLineInfo lineInfo = r as IJsonLineInfo;
JContainer parent = this;
@@ -385,6 +386,7 @@ namespace Newtonsoft.Json.Linq
break;
case JsonToken.StartArray:
JArray a = new JArray();
+ a.SetLineInfo(lineInfo);
parent.AddObjectSkipNotify(a);
parent = a;
break;
@@ -397,6 +399,7 @@ namespace Newtonsoft.Json.Linq
break;
case JsonToken.StartObject:
JObject o = new JObject();
+ o.SetLineInfo(lineInfo);
parent.AddObjectSkipNotify(o);
parent = o;
break;
@@ -408,6 +411,7 @@ namespace Newtonsoft.Json.Linq
break;
case JsonToken.StartConstructor:
JConstructor constructor = new JConstructor(r.Value.ToString());
+ constructor.SetLineInfo(constructor);
parent.AddObjectSkipNotify(constructor);
parent = constructor;
break;
@@ -422,19 +426,28 @@ namespace Newtonsoft.Json.Linq
case JsonToken.Float:
case JsonToken.Date:
case JsonToken.Boolean:
- parent.AddObjectSkipNotify(new JValue(r.Value));
+ JValue v = new JValue(r.Value);
+ v.SetLineInfo(lineInfo);
+ parent.AddObjectSkipNotify(v);
break;
case JsonToken.Comment:
- parent.AddObjectSkipNotify(JValue.CreateComment(r.Value.ToString()));
+ v = JValue.CreateComment(r.Value.ToString());
+ v.SetLineInfo(lineInfo);
+ parent.AddObjectSkipNotify(v);
break;
case JsonToken.Null:
- parent.AddObjectSkipNotify(new JValue(null, JsonTokenType.Null));
+ v = new JValue(null, JsonTokenType.Null);
+ v.SetLineInfo(lineInfo);
+ parent.AddObjectSkipNotify(v);
break;
case JsonToken.Undefined:
- parent.AddObjectSkipNotify(new JValue(null, JsonTokenType.Undefined));
+ v = new JValue(null, JsonTokenType.Undefined);
+ v.SetLineInfo(lineInfo);
+ parent.AddObjectSkipNotify(v);
break;
case JsonToken.PropertyName:
JProperty property = new JProperty(r.Value.ToString());
+ property.SetLineInfo(lineInfo);
parent.AddObjectSkipNotify(property);
parent = property;
break;
diff --git a/Src/Newtonsoft.Json/Linq/JObject.cs b/Src/Newtonsoft.Json/Linq/JObject.cs
index 99315540..3798f59e 100644
--- a/Src/Newtonsoft.Json/Linq/JObject.cs
+++ b/Src/Newtonsoft.Json/Linq/JObject.cs
@@ -196,10 +196,12 @@ namespace Newtonsoft.Json.Linq
"Error reading JObject from JsonReader. Current JsonReader item is not an object: {0}".FormatWith(
CultureInfo.InvariantCulture, reader.TokenType));
+ JObject o = new JObject();
+ o.SetLineInfo(reader as IJsonLineInfo);
+
if (!reader.Read())
throw new Exception("Error reading JObject from JsonReader.");
- JObject o = new JObject();
o.ReadContentFrom(reader);
return o;
diff --git a/Src/Newtonsoft.Json/Linq/JProperty.cs b/Src/Newtonsoft.Json/Linq/JProperty.cs
index 61c01101..4ac2ccdc 100644
--- a/Src/Newtonsoft.Json/Linq/JProperty.cs
+++ b/Src/Newtonsoft.Json/Linq/JProperty.cs
@@ -186,6 +186,7 @@ namespace Newtonsoft.Json.Linq
CultureInfo.InvariantCulture, reader.TokenType));
JProperty p = new JProperty((string)reader.Value);
+ p.SetLineInfo(reader as IJsonLineInfo);
if (!reader.Read())
throw new Exception("Error reading JProperty from JsonReader.");
diff --git a/Src/Newtonsoft.Json/Linq/JToken.cs b/Src/Newtonsoft.Json/Linq/JToken.cs
index beb7201b..ff963b99 100644
--- a/Src/Newtonsoft.Json/Linq/JToken.cs
+++ b/Src/Newtonsoft.Json/Linq/JToken.cs
@@ -38,12 +38,15 @@ namespace Newtonsoft.Json.Linq
///
/// Represents an abstract JSON token.
///
- public abstract class JToken : IJEnumerable
+ public abstract class JToken : IJEnumerable, IJsonLineInfo
{
private JContainer _parent;
internal JToken _next;
private static JTokenEqualityComparer _equalityComparer;
+ private int? _lineNumber;
+ private int? _linePosition;
+
///
/// Gets a comparer that can compare two tokens for value equality.
///
@@ -797,5 +800,34 @@ namespace Newtonsoft.Json.Linq
// TODO: loading constructor and parameters?
throw new Exception("Error reading JToken from JsonReader. Unexpected token: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
}
+
+ internal void SetLineInfo(IJsonLineInfo lineInfo)
+ {
+ if (lineInfo == null || !lineInfo.HasLineInfo())
+ return;
+
+ SetLineInfo(lineInfo.LineNumber, lineInfo.LinePosition);
+ }
+
+ internal void SetLineInfo(int lineNumber, int linePosition)
+ {
+ _lineNumber = lineNumber;
+ _linePosition = linePosition;
+ }
+
+ bool IJsonLineInfo.HasLineInfo()
+ {
+ return (_lineNumber != null && _linePosition != null);
+ }
+
+ int IJsonLineInfo.LineNumber
+ {
+ get { return _lineNumber ?? 0; }
+ }
+
+ int IJsonLineInfo.LinePosition
+ {
+ get { return _linePosition ?? 0; }
+ }
}
}
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Linq/JsonTokenReader.cs b/Src/Newtonsoft.Json/Linq/JsonTokenReader.cs
index 6cb6bae7..ce1814a6 100644
--- a/Src/Newtonsoft.Json/Linq/JsonTokenReader.cs
+++ b/Src/Newtonsoft.Json/Linq/JsonTokenReader.cs
@@ -9,7 +9,7 @@ namespace Newtonsoft.Json.Linq
///
/// Represents a reader that provides fast, non-cached, forward-only access to serialized Json data.
///
- public class JsonTokenReader : JsonReader
+ public class JsonTokenReader : JsonReader, IJsonLineInfo
{
private readonly JToken _root;
private JToken _parent;
@@ -75,6 +75,11 @@ namespace Newtonsoft.Json.Linq
return false;
}
+ private bool IsEndElement
+ {
+ get { return (_current == _parent); }
+ }
+
private JsonToken? GetEndToken(JContainer c)
{
switch (c.Type)
@@ -171,5 +176,44 @@ namespace Newtonsoft.Json.Linq
throw MiscellaneousUtils.CreateArgumentOutOfRangeException("Type", token.Type, "Unexpected JsonTokenType.");
}
}
+
+ bool IJsonLineInfo.HasLineInfo()
+ {
+ if (CurrentState == State.Start)
+ return false;
+
+ IJsonLineInfo info = IsEndElement ? null : _current;
+ return (info != null && info.HasLineInfo());
+ }
+
+ int IJsonLineInfo.LineNumber
+ {
+ get
+ {
+ if (CurrentState == State.Start)
+ return 0;
+
+ IJsonLineInfo info = IsEndElement ? null : _current;
+ if (info != null)
+ return info.LineNumber;
+
+ return 0;
+ }
+ }
+
+ int IJsonLineInfo.LinePosition
+ {
+ get
+ {
+ if (CurrentState == State.Start)
+ return 0;
+
+ IJsonLineInfo info = IsEndElement ? null : _current;
+ if (info != null)
+ return info.LinePosition;
+
+ return 0;
+ }
+ }
}
}
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj
index fe3dc84a..a656114a 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Compact.csproj
@@ -56,6 +56,7 @@
+
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj
index f49c490a..9c4d5ae0 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.Silverlight.csproj
@@ -55,6 +55,7 @@
+
diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
index c3ea762b..a9e265b0 100644
--- a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
+++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
@@ -74,6 +74,7 @@
+
diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaException.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaException.cs
index 7afaf942..881cbac4 100644
--- a/Src/Newtonsoft.Json/Schema/JsonSchemaException.cs
+++ b/Src/Newtonsoft.Json/Schema/JsonSchemaException.cs
@@ -32,6 +32,9 @@ namespace Newtonsoft.Json.Schema
///
public class JsonSchemaException : Exception
{
+ public int LineNumber { get; private set; }
+ public int LinePosition { get; private set; }
+
///
/// Initializes a new instance of the class.
///
@@ -59,5 +62,12 @@ namespace Newtonsoft.Json.Schema
: base(message, innerException)
{
}
+
+ internal JsonSchemaException(string message, Exception innerException, int lineNumber, int linePosition)
+ : base(message, innerException)
+ {
+ LineNumber = lineNumber;
+ LinePosition = linePosition;
+ }
}
}
\ No newline at end of file
diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaGenerator.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaGenerator.cs
index 71fd4db8..6d142fff 100644
--- a/Src/Newtonsoft.Json/Schema/JsonSchemaGenerator.cs
+++ b/Src/Newtonsoft.Json/Schema/JsonSchemaGenerator.cs
@@ -253,8 +253,11 @@ namespace Newtonsoft.Json.Schema
CurrentSchema.Properties.Add(mapping.MappingName, propertySchema);
}
}
+
+ if (type.IsSealed)
+ CurrentSchema.AllowAdditionalProperties = false;
}
- else if (CurrentSchema.Type == JsonSchemaType.Integer && type.IsEnum)
+ else if (CurrentSchema.Type == JsonSchemaType.Integer && type.IsEnum && !type.IsDefined(typeof(FlagsAttribute), true))
{
CurrentSchema.Enum = new List();
CurrentSchema.Options = new Dictionary();
diff --git a/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs b/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs
index d7d1dc4e..02b53ff2 100644
--- a/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs
+++ b/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs
@@ -59,11 +59,14 @@ namespace Newtonsoft.Json.Utilities
if (initialType == typeof(Guid) && (targetType == typeof(Guid) || targetType == typeof(string)))
return true;
+ if (initialType == typeof(Type) && targetType == typeof(string))
+ return true;
+
#if !PocketPC
// see if source or target types have a TypeConverter that converts between the two
TypeConverter toConverter = GetConverter(initialType);
- if (toConverter != null && toConverter.CanConvertTo(targetType))
+ if (toConverter != null && !IsComponentConverter(toConverter) && toConverter.CanConvertTo(targetType))
{
if (allowTypeNameToString || toConverter.GetType() != typeof(TypeConverter))
return true;
@@ -71,7 +74,7 @@ namespace Newtonsoft.Json.Utilities
TypeConverter fromConverter = GetConverter(targetType);
- if (fromConverter != null && fromConverter.CanConvertFrom(initialType))
+ if (fromConverter != null && !IsComponentConverter(fromConverter) && fromConverter.CanConvertFrom(initialType))
return true;
#endif
@@ -85,6 +88,15 @@ namespace Newtonsoft.Json.Utilities
return false;
}
+ private static bool IsComponentConverter(TypeConverter converter)
+ {
+#if !SILVERLIGHT && !PocketPC
+ return (converter is ComponentConverter);
+#else
+ return false;
+#endif
+ }
+
#region Convert
///
/// Converts the value to the specified type.
diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs
index a79bb489..f67bda32 100644
--- a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs
+++ b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs
@@ -231,7 +231,7 @@ namespace Newtonsoft.Json.Utilities
return genericListType.GetGenericArguments()[0];
}
- else if (typeof(IList).IsAssignableFrom(type))
+ else if (typeof(ICollection).IsAssignableFrom(type))
{
return null;
}