From 40c24307dec072e4edb92a5dc18bedad60f99980 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Mon, 23 Dec 2013 22:42:38 +1300 Subject: [PATCH] -Fixed error when wrapping an exception in a JsonConverter --- .../Properties/AssemblyInfo.cs | 2 +- .../Serialization/JsonSerializerTest.cs | 2 +- .../SerializationErrorHandlingTests.cs | 151 ++++++++++++++++++ .../Linq/JsonPath/FieldMultipleFilter.cs | 6 +- .../Properties/AssemblyInfo.cs | 2 +- .../Serialization/ErrorContext.cs | 2 +- .../JsonSerializerInternalReader.cs | 4 + .../JsonSerializerInternalWriter.cs | 23 ++- 8 files changed, 186 insertions(+), 6 deletions(-) diff --git a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs index 4922c0cb..fc0b2a81 100644 --- a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs +++ b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs @@ -75,4 +75,4 @@ using System.Security; // by using the '*' as shown below: [assembly: AssemblyVersion("4.5.0.0")] -[assembly: AssemblyFileVersion("5.0.8.16815")] +[assembly: AssemblyFileVersion("5.0.8.16823")] diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index 07a9d0b8..9c9f92c8 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -4257,7 +4257,7 @@ To fix this error either change the environment to be fully trusted, change the #if !NET20 dateTimeOffsetText = @"2000-12-20T22:59:59+02:00"; #else - dateTimeOffsetText = @"12/20/2000 22:59:59 +02:00"; + dateTimeOffsetText = @"12/20/2000 22:59:59 +02:00"; #endif ISerializableTestObject o = new ISerializableTestObject("String!", int.MinValue, dateTimeOffset, person); diff --git a/Src/Newtonsoft.Json.Tests/Serialization/SerializationErrorHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/SerializationErrorHandlingTests.cs index cd993214..9fb267b8 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/SerializationErrorHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/SerializationErrorHandlingTests.cs @@ -715,6 +715,157 @@ namespace Newtonsoft.Json.Tests.Serialization @"Unterminated string. Expected delimiter: "". Path '', line 1, position 3.", () => { ErrorTestObject obj = s.Deserialize(jReader); }); } + + public class RootThing + { + public Something Something { get; set; } + } + + public class RootSomethingElse + { + public SomethingElse SomethingElse { get; set; } + } + + /// + /// This could be an object we are passing up in an interface. + /// + [JsonConverter(typeof(SomethingConverter))] + public class Something + { + public class SomethingConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return true; + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + try + { + // Do own stuff. + // Then call deserialise for inner object. + var innerObject = serializer.Deserialize(reader, typeof(SomethingElse)); + + return null; + } + catch (Exception ex) + { + // If we get an error wrap it in something less scary. + throw new Exception("An error occurred.", ex); + } + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + try + { + Something s = (Something)value; + + // Do own stuff. + // Then call serialise for inner object. + serializer.Serialize(writer, s.RootSomethingElse); + } + catch (Exception ex) + { + // If we get an error wrap it in something less scary. + throw new Exception("An error occurred.", ex); + } + } + } + + public RootSomethingElse RootSomethingElse { get; set; } + + public Something() + { + this.RootSomethingElse = new RootSomethingElse(); + } + } + + /// + /// This is an object that is contained in the interface object. + /// + [JsonConverter(typeof(SomethingElseConverter))] + public class SomethingElse + { + public class SomethingElseConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return true; + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + throw new NotImplementedException(); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new NotImplementedException(); + } + } + + } + + [Test] + public void DeserializeWrappingErrorsAndErrorHandling() + { + var serialiser = JsonSerializer.Create(new JsonSerializerSettings() { }); + + string foo = "{ something: { rootSomethingElse { somethingElse: 0 } } }"; + var reader = new System.IO.StringReader(foo); + + ExceptionAssert.Throws( + "An error occurred.", + () => { serialiser.Deserialize(reader, typeof(Something)); }); + } + + [Test] + public void SerializeWrappingErrorsAndErrorHandling() + { + var serialiser = JsonSerializer.Create(new JsonSerializerSettings() { }); + + Something s = new Something + { + RootSomethingElse = new RootSomethingElse + { + SomethingElse = new SomethingElse() + } + }; + RootThing r = new RootThing + { + Something = s + }; + + var writer = new System.IO.StringWriter(); + + ExceptionAssert.Throws( + "An error occurred.", + () => { serialiser.Serialize(writer, r); }); + } + + [Test] + public void DeserializeRootConverter() + { + SomethingElse result = JsonConvert.DeserializeObject("{}", new JsonSerializerSettings + { + Error = (o, e) => { e.ErrorContext.Handled = true; } + }); + + Assert.IsNull(result); + } + + [Test] + public void SerializeRootConverter() + { + string result = JsonConvert.SerializeObject(new SomethingElse(), new JsonSerializerSettings + { + Error = (o, e) => { e.ErrorContext.Handled = true; } + }); + + Assert.AreEqual(string.Empty, result); + } } internal interface IErrorPerson2 diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/FieldMultipleFilter.cs b/Src/Newtonsoft.Json/Linq/JsonPath/FieldMultipleFilter.cs index 7480a514..8349f4ae 100644 --- a/Src/Newtonsoft.Json/Linq/JsonPath/FieldMultipleFilter.cs +++ b/Src/Newtonsoft.Json/Linq/JsonPath/FieldMultipleFilter.cs @@ -1,6 +1,10 @@ using System.Collections.Generic; using System.Globalization; +#if NET20 +using Newtonsoft.Json.Utilities.LinqBridge; +#else using System.Linq; +#endif using Newtonsoft.Json.Utilities; namespace Newtonsoft.Json.Linq.JsonPath @@ -30,7 +34,7 @@ namespace Newtonsoft.Json.Linq.JsonPath else { if (errorWhenNoMatch) - throw new JsonException("Properties {0} not valid on {1}.".FormatWith(CultureInfo.InvariantCulture, string.Join(", ", Names.Select(n => "'" + n + "'")), t.GetType().Name)); + throw new JsonException("Properties {0} not valid on {1}.".FormatWith(CultureInfo.InvariantCulture, string.Join(", ", Names.Select(n => "'" + n + "'").ToArray()), t.GetType().Name)); } } } diff --git a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs index 8e31cb5f..d3d2b37e 100644 --- a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs +++ b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs @@ -91,5 +91,5 @@ using System.Security; // by using the '*' as shown below: [assembly: AssemblyVersion("4.5.0.0")] -[assembly: AssemblyFileVersion("5.0.8.16815")] +[assembly: AssemblyFileVersion("5.0.8.16823")] [assembly: CLSCompliant(true)] diff --git a/Src/Newtonsoft.Json/Serialization/ErrorContext.cs b/Src/Newtonsoft.Json/Serialization/ErrorContext.cs index 3bdf11ab..bcb2fbbe 100644 --- a/Src/Newtonsoft.Json/Serialization/ErrorContext.cs +++ b/Src/Newtonsoft.Json/Serialization/ErrorContext.cs @@ -43,7 +43,7 @@ namespace Newtonsoft.Json.Serialization internal bool Traced { get; set; } /// - /// Gets or sets the error. + /// Gets the error. /// /// The error. public Exception Error { get; private set; } diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index 10f06d34..3e1c084a 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -174,6 +174,10 @@ namespace Newtonsoft.Json.Serialization } else { + // clear context in case serializer is being used inside a converter + // if the converter wraps the error then not clearing the context will cause this error: + // "Current error context error is different to requested error." + ClearErrorContext(); throw; } } diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs index c6d99bf0..33466430 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs @@ -65,7 +65,28 @@ namespace Newtonsoft.Json.Serialization if (objectType != null) _rootContract = Serializer._contractResolver.ResolveContract(objectType); - SerializeValue(jsonWriter, value, GetContractSafe(value), null, null, null); + JsonContract contract = GetContractSafe(value); + + try + { + + SerializeValue(jsonWriter, value, contract, null, null, null); + } + catch (Exception ex) + { + if (IsErrorHandled(null, contract, null, null, jsonWriter.Path, ex)) + { + HandleError(jsonWriter, 0); + } + else + { + // clear context in case serializer is being used inside a converter + // if the converter wraps the error then not clearing the context will cause this error: + // "Current error context error is different to requested error." + ClearErrorContext(); + throw; + } + } } private JsonSerializerProxy GetInternalSerializer()