-Improved error handling to return incomplete values at end of JSON content
This commit is contained in:
@@ -72,5 +72,5 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("4.5.0.0")]
|
||||
#if !PocketPC
|
||||
[assembly: AssemblyFileVersion("4.5.8.15201")]
|
||||
[assembly: AssemblyFileVersion("4.5.8.15204")]
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -181,7 +181,7 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
[Test]
|
||||
public void DynamicCamelCasePropertyNames()
|
||||
{
|
||||
dynamic o = new DynamicTests.TestDynamicObject();
|
||||
dynamic o = new TestDynamicObject();
|
||||
o.Text = "Text!";
|
||||
o.Integer = int.MaxValue;
|
||||
|
||||
|
||||
@@ -50,77 +50,6 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
[TestFixture]
|
||||
public class DynamicTests : TestFixtureBase
|
||||
{
|
||||
public class DynamicChildObject
|
||||
{
|
||||
public string Text { get; set; }
|
||||
public int Integer { get; set; }
|
||||
}
|
||||
|
||||
public class TestDynamicObject : DynamicObject
|
||||
{
|
||||
private readonly Dictionary<string, object> _members;
|
||||
|
||||
public int Int;
|
||||
[JsonProperty]
|
||||
public bool Explicit;
|
||||
public DynamicChildObject ChildObject { get; set; }
|
||||
|
||||
internal Dictionary<string, object> Members
|
||||
{
|
||||
get { return _members; }
|
||||
}
|
||||
|
||||
public TestDynamicObject()
|
||||
{
|
||||
_members = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetDynamicMemberNames()
|
||||
{
|
||||
return _members.Keys.Union(new[] { "Int", "ChildObject" });
|
||||
}
|
||||
|
||||
public override bool TryConvert(ConvertBinder binder, out object result)
|
||||
{
|
||||
Type targetType = binder.Type;
|
||||
|
||||
if (targetType == typeof(IDictionary<string, object>) ||
|
||||
targetType == typeof(IDictionary))
|
||||
{
|
||||
result = new Dictionary<string, object>(_members);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.TryConvert(binder, out result);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool TryDeleteMember(DeleteMemberBinder binder)
|
||||
{
|
||||
return _members.Remove(binder.Name);
|
||||
}
|
||||
|
||||
public override bool TryGetMember(GetMemberBinder binder, out object result)
|
||||
{
|
||||
return _members.TryGetValue(binder.Name, out result);
|
||||
}
|
||||
|
||||
public override bool TrySetMember(SetMemberBinder binder, object value)
|
||||
{
|
||||
_members[binder.Name] = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class ErrorSettingDynamicObject : DynamicObject
|
||||
{
|
||||
public override bool TrySetMember(SetMemberBinder binder, object value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeDynamicObject()
|
||||
{
|
||||
@@ -317,5 +246,76 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
Assert.AreEqual(false, foo.Values["retweeted"]);
|
||||
}
|
||||
}
|
||||
|
||||
public class DynamicChildObject
|
||||
{
|
||||
public string Text { get; set; }
|
||||
public int Integer { get; set; }
|
||||
}
|
||||
|
||||
public class TestDynamicObject : DynamicObject
|
||||
{
|
||||
private readonly Dictionary<string, object> _members;
|
||||
|
||||
public int Int;
|
||||
[JsonProperty]
|
||||
public bool Explicit;
|
||||
public DynamicChildObject ChildObject { get; set; }
|
||||
|
||||
internal Dictionary<string, object> Members
|
||||
{
|
||||
get { return _members; }
|
||||
}
|
||||
|
||||
public TestDynamicObject()
|
||||
{
|
||||
_members = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetDynamicMemberNames()
|
||||
{
|
||||
return _members.Keys.Union(new[] { "Int", "ChildObject" });
|
||||
}
|
||||
|
||||
public override bool TryConvert(ConvertBinder binder, out object result)
|
||||
{
|
||||
Type targetType = binder.Type;
|
||||
|
||||
if (targetType == typeof(IDictionary<string, object>) ||
|
||||
targetType == typeof(IDictionary))
|
||||
{
|
||||
result = new Dictionary<string, object>(_members);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.TryConvert(binder, out result);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool TryDeleteMember(DeleteMemberBinder binder)
|
||||
{
|
||||
return _members.Remove(binder.Name);
|
||||
}
|
||||
|
||||
public override bool TryGetMember(GetMemberBinder binder, out object result)
|
||||
{
|
||||
return _members.TryGetValue(binder.Name, out result);
|
||||
}
|
||||
|
||||
public override bool TrySetMember(SetMemberBinder binder, object value)
|
||||
{
|
||||
_members[binder.Name] = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class ErrorSettingDynamicObject : DynamicObject
|
||||
{
|
||||
public override bool TrySetMember(SetMemberBinder binder, object value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -6447,6 +6447,26 @@ Parameter name: value",
|
||||
}
|
||||
#endif
|
||||
|
||||
[Test]
|
||||
public void AdditionalContentAfterFinish()
|
||||
{
|
||||
ExceptionAssert.Throws<JsonException>(
|
||||
"Additional text found in JSON string after finishing deserializing object.",
|
||||
() =>
|
||||
{
|
||||
string json = "[{},1]";
|
||||
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
serializer.CheckAdditionalContent = true;
|
||||
|
||||
var reader = new JsonTextReader(new StringReader(json));
|
||||
reader.Read();
|
||||
reader.Read();
|
||||
|
||||
serializer.Deserialize(reader, typeof (MyType));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeRelativeUri()
|
||||
{
|
||||
|
||||
@@ -552,7 +552,7 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
{
|
||||
IList<string> errors = new List<string>();
|
||||
|
||||
const string input = "{\"events\":[{\"code\":64411,\"prio";
|
||||
const string input = "{\"events\":[{\"code\":64411},{\"code\":64411,\"prio";
|
||||
|
||||
const int maxDepth = 256;
|
||||
using (var jsonTextReader = new JsonTextReader(new StringReader(input)) {MaxDepth = maxDepth})
|
||||
@@ -563,14 +563,84 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
errors.Add(e.ErrorContext.Error.Message);
|
||||
e.ErrorContext.Handled = true;
|
||||
};
|
||||
|
||||
jsonSerializer.Deserialize(jsonTextReader, typeof (LogMessage));
|
||||
|
||||
LogMessage logMessage = jsonSerializer.Deserialize<LogMessage>(jsonTextReader);
|
||||
|
||||
Assert.IsNotNull(logMessage.Events);
|
||||
Assert.AreEqual(1, logMessage.Events.Count);
|
||||
Assert.AreEqual("64411", logMessage.Events[0].Code);
|
||||
}
|
||||
|
||||
Assert.AreEqual(3, errors.Count);
|
||||
Assert.AreEqual(@"Unterminated string. Expected delimiter: "". Path 'events[1].code', line 1, position 45.", errors[0]);
|
||||
Assert.AreEqual(@"Unexpected end when deserializing array. Path 'events[1].code', line 1, position 45.", errors[1]);
|
||||
Assert.AreEqual(@"Unexpected end when deserializing object. Path 'events[1].code', line 1, position 45.", errors[2]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ErrorHandlingEndOfContentDictionary()
|
||||
{
|
||||
IList<string> errors = new List<string>();
|
||||
|
||||
const string input = "{\"events\":{\"code\":64411},\"events2\":{\"code\":64412,";
|
||||
|
||||
const int maxDepth = 256;
|
||||
using (var jsonTextReader = new JsonTextReader(new StringReader(input)) {MaxDepth = maxDepth})
|
||||
{
|
||||
JsonSerializer jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings {MaxDepth = maxDepth});
|
||||
jsonSerializer.Error += (sender, e) =>
|
||||
{
|
||||
errors.Add(e.ErrorContext.Error.Message);
|
||||
e.ErrorContext.Handled = true;
|
||||
};
|
||||
|
||||
IDictionary<string, LogEvent> logEvents = jsonSerializer.Deserialize<IDictionary<string, LogEvent>>(jsonTextReader);
|
||||
|
||||
Assert.IsNotNull(logEvents);
|
||||
Assert.AreEqual(2, logEvents.Count);
|
||||
Assert.AreEqual("64411", logEvents["events"].Code);
|
||||
Assert.AreEqual("64412", logEvents["events2"].Code);
|
||||
}
|
||||
|
||||
Assert.AreEqual(2, errors.Count);
|
||||
Assert.AreEqual(@"Unterminated string. Expected delimiter: "". Path 'events[0].code', line 1, position 30.", errors[0]);
|
||||
Assert.AreEqual(@"Unexpected end when deserializing object. Path 'events[0].code', line 1, position 30.", errors[1]);
|
||||
Assert.AreEqual(@"Unexpected end when deserializing object. Path 'events2.code', line 1, position 49.", errors[0]);
|
||||
Assert.AreEqual(@"Unexpected end when deserializing object. Path 'events2.code', line 1, position 49.", errors[1]);
|
||||
}
|
||||
|
||||
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
|
||||
[Test]
|
||||
public void ErrorHandlingEndOfContentDynamic()
|
||||
{
|
||||
IList<string> errors = new List<string>();
|
||||
|
||||
string json = @"{
|
||||
""Explicit"": true,
|
||||
""Decimal"": 99.9,
|
||||
""Int"": 1,
|
||||
""ChildObject"": {
|
||||
""Integer"": 123";
|
||||
|
||||
TestDynamicObject newDynamicObject = JsonConvert.DeserializeObject<TestDynamicObject>(json, new JsonSerializerSettings
|
||||
{
|
||||
Error = (sender, e) =>
|
||||
{
|
||||
errors.Add(e.ErrorContext.Error.Message);
|
||||
e.ErrorContext.Handled = true;
|
||||
}
|
||||
});
|
||||
Assert.AreEqual(true, newDynamicObject.Explicit);
|
||||
|
||||
dynamic d = newDynamicObject;
|
||||
|
||||
Assert.AreEqual(99.9, d.Decimal);
|
||||
Assert.AreEqual(1, d.Int);
|
||||
Assert.AreEqual(123, d.ChildObject.Integer);
|
||||
|
||||
Assert.AreEqual(2, errors.Count);
|
||||
Assert.AreEqual(@"Unexpected end when deserializing object. Path 'ChildObject.Integer', line 6, position 19.", errors[0]);
|
||||
Assert.AreEqual(@"Unexpected end when deserializing object. Path 'ChildObject.Integer', line 6, position 19.", errors[1]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public class ThrowingReader : TextReader
|
||||
@@ -639,6 +709,7 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
public class LogMessage
|
||||
{
|
||||
public string DeviceId { get; set; }
|
||||
public IList<LogEvent> Events { get; set; }
|
||||
}
|
||||
|
||||
public class LogEvent
|
||||
|
||||
@@ -91,7 +91,7 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("4.5.0.0")]
|
||||
#if !PocketPC
|
||||
[assembly: AssemblyFileVersion("4.5.8.15201")]
|
||||
[assembly: AssemblyFileVersion("4.5.8.15204")]
|
||||
#endif
|
||||
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
@@ -813,6 +813,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
|
||||
JsonConverter dictionaryValueConverter = contract.ItemConverter ?? GetConverter(contract.ItemContract, null, contract, containerProperty);
|
||||
|
||||
bool finished = false;
|
||||
do
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
@@ -852,15 +853,18 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
case JsonToken.Comment:
|
||||
break;
|
||||
case JsonToken.EndObject:
|
||||
contract.InvokeOnDeserialized(dictionary, Serializer.Context);
|
||||
|
||||
return dictionary;
|
||||
finished = true;
|
||||
break;
|
||||
default:
|
||||
throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
|
||||
}
|
||||
} while (reader.Read());
|
||||
} while (!finished && reader.Read());
|
||||
|
||||
throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object.");
|
||||
if (!finished)
|
||||
ThrowUnexpectedEndException(reader, contract, dictionary, "Unexpected end when deserializing object.");
|
||||
|
||||
contract.InvokeOnDeserialized(dictionary, Serializer.Context);
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
private object PopulateMultidimensionalArray(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id)
|
||||
@@ -880,7 +884,8 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
listStack.Push(list);
|
||||
IList currentList = list;
|
||||
|
||||
while (true)
|
||||
bool finished = false;
|
||||
do
|
||||
{
|
||||
int initialDepth = reader.Depth;
|
||||
|
||||
@@ -962,9 +967,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
}
|
||||
else
|
||||
{
|
||||
contract.InvokeOnDeserialized(list, Serializer.Context);
|
||||
|
||||
return list;
|
||||
finished = true;
|
||||
}
|
||||
break;
|
||||
case JsonToken.Comment:
|
||||
@@ -978,9 +981,28 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!finished);
|
||||
|
||||
throw JsonSerializationException.Create(reader, "Unexpected end when deserializing array.");
|
||||
if (!finished)
|
||||
ThrowUnexpectedEndException(reader, contract, list, "Unexpected end when deserializing array.");
|
||||
|
||||
contract.InvokeOnDeserialized(list, Serializer.Context);
|
||||
return list;
|
||||
}
|
||||
|
||||
private void ThrowUnexpectedEndException(JsonReader reader, JsonContract contract, object currentObject, string message)
|
||||
{
|
||||
try
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, message);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (IsErrorHandled(currentObject, contract, null, reader.Path, ex))
|
||||
HandleError(reader, false, 0);
|
||||
else
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private object PopulateList(IWrappedCollection wrappedList, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id)
|
||||
@@ -1006,7 +1028,8 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
|
||||
int? previousErrorIndex = null;
|
||||
|
||||
while (true)
|
||||
bool finished = false;
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1015,9 +1038,8 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.EndArray:
|
||||
contract.InvokeOnDeserialized(list, Serializer.Context);
|
||||
|
||||
return list;
|
||||
finished = true;
|
||||
break;
|
||||
case JsonToken.Comment:
|
||||
break;
|
||||
default:
|
||||
@@ -1061,9 +1083,13 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!finished);
|
||||
|
||||
throw JsonSerializationException.Create(reader, "Unexpected end when deserializing array.");
|
||||
if (!finished)
|
||||
ThrowUnexpectedEndException(reader, contract, list, "Unexpected end when deserializing array.");
|
||||
|
||||
contract.InvokeOnDeserialized(list, Serializer.Context);
|
||||
return list;
|
||||
}
|
||||
|
||||
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
|
||||
@@ -1080,7 +1106,7 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
|
||||
SerializationInfo serializationInfo = new SerializationInfo(contract.UnderlyingType, GetFormatterConverter());
|
||||
|
||||
bool exit = false;
|
||||
bool finished = false;
|
||||
do
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
@@ -1095,12 +1121,15 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
case JsonToken.Comment:
|
||||
break;
|
||||
case JsonToken.EndObject:
|
||||
exit = true;
|
||||
finished = true;
|
||||
break;
|
||||
default:
|
||||
throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
|
||||
}
|
||||
} while (!exit && reader.Read());
|
||||
} while (!finished && reader.Read());
|
||||
|
||||
if (!finished)
|
||||
ThrowUnexpectedEndException(reader, contract, serializationInfo, "Unexpected end when deserializing object.");
|
||||
|
||||
if (contract.ISerializableCreator == null)
|
||||
throw JsonSerializationException.Create(reader, "ISerializable type '{0}' does not have a valid constructor. To correctly implement ISerializable a constructor that takes SerializationInfo and StreamingContext parameters should be present.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
||||
@@ -1139,7 +1168,7 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
|
||||
int initialDepth = reader.Depth;
|
||||
|
||||
bool exit = false;
|
||||
bool finished = false;
|
||||
do
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
@@ -1189,12 +1218,15 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
}
|
||||
break;
|
||||
case JsonToken.EndObject:
|
||||
exit = true;
|
||||
finished = true;
|
||||
break;
|
||||
default:
|
||||
throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
|
||||
}
|
||||
} while (!exit && reader.Read());
|
||||
} while (!finished && reader.Read());
|
||||
|
||||
if (!finished)
|
||||
ThrowUnexpectedEndException(reader, contract, newObject, "Unexpected end when deserializing object.");
|
||||
|
||||
contract.InvokeOnDeserialized(newObject, Serializer.Context);
|
||||
|
||||
@@ -1450,6 +1482,7 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
|
||||
int initialDepth = reader.Depth;
|
||||
|
||||
bool finished = false;
|
||||
do
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
@@ -1495,21 +1528,23 @@ To fix this error either change the environment to be fully trusted, change the
|
||||
}
|
||||
break;
|
||||
case JsonToken.EndObject:
|
||||
{
|
||||
EndObject(newObject, reader, contract, initialDepth, propertiesPresence);
|
||||
|
||||
contract.InvokeOnDeserialized(newObject, Serializer.Context);
|
||||
return newObject;
|
||||
}
|
||||
finished = true;
|
||||
break;
|
||||
case JsonToken.Comment:
|
||||
// ignore
|
||||
break;
|
||||
default:
|
||||
throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
|
||||
}
|
||||
} while (reader.Read());
|
||||
} while (!finished && reader.Read());
|
||||
|
||||
throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object.");
|
||||
if (!finished)
|
||||
ThrowUnexpectedEndException(reader, contract, newObject, "Unexpected end when deserializing object.");
|
||||
|
||||
EndObject(newObject, reader, contract, initialDepth, propertiesPresence);
|
||||
|
||||
contract.InvokeOnDeserialized(newObject, Serializer.Context);
|
||||
return newObject;
|
||||
}
|
||||
|
||||
private void EndObject(object newObject, JsonReader reader, JsonObjectContract contract, int initialDepth, Dictionary<JsonProperty, PropertyPresence> propertiesPresence)
|
||||
|
||||
Reference in New Issue
Block a user