From e857e48564abc564e206eb1e87faf6306e976539 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Sun, 17 Mar 2013 14:25:01 +1300 Subject: [PATCH] -Changed serialization callbacks on JsonContract to delegates -Added Obsolete attributes to old serialization methods on JsonContract -Added VS and ReSharper settings files -Fixed converting null JSON value to XML -Fixed tests --- .../Bson/BsonWriterTests.cs | 2 +- .../Converters/XmlNodeConverterTest.cs | 21 ++ Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs | 2 +- .../Properties/AssemblyInfo.cs | 2 +- Src/Newtonsoft.Json.sln.DotSettings | 5 + Src/Newtonsoft.Json.vssettings | 13 ++ .../Converters/XmlNodeConverter.cs | 3 + .../Properties/AssemblyInfo.cs | 2 +- .../Serialization/DefaultContractResolver.cs | 46 ++--- .../Serialization/JsonContract.cs | 183 ++++++++++-------- .../Serialization/JsonDictionaryContract.cs | 2 +- .../JsonSerializerInternalReader.cs | 4 +- .../Utilities/TypeExtensions.cs | 9 + 13 files changed, 182 insertions(+), 112 deletions(-) create mode 100644 Src/Newtonsoft.Json.sln.DotSettings create mode 100644 Src/Newtonsoft.Json.vssettings diff --git a/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs b/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs index edbaae08..4752121a 100644 --- a/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs @@ -711,7 +711,7 @@ namespace Newtonsoft.Json.Tests.Bson Assert.IsTrue(reader.Read()); Assert.AreEqual(JsonToken.Bytes, reader.TokenType); - Assert.AreEqual(new byte[] { 246, 255, 255, 255, 255, 255, 255, 31, 178, 33, 203, 40, 89, 132, 196, 174, 3, 138, 68, 52, 47, 76, 78, 158, 62, 1 }, reader.Value); + CollectionAssert.AreEqual(new byte[] { 246, 255, 255, 255, 255, 255, 255, 31, 178, 33, 203, 40, 89, 132, 196, 174, 3, 138, 68, 52, 47, 76, 78, 158, 62, 1 }, (byte[])reader.Value); Assert.AreEqual(i, new BigInteger((byte[])reader.Value)); Assert.IsTrue(reader.Read()); diff --git a/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs index 610d9343..f3cc600d 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs @@ -1902,6 +1902,27 @@ namespace Newtonsoft.Json.Tests.Converters Assert.AreEqual(@"{""root"":{""@xmlns"":""http://www.example.com/ns"",""a"":null,""bns:b"":{""@xmlns:bns"":""http://www.example.com/ns""},""c"":null}}", json2); #endif } + +#if !NET20 + class NullableXml + { + public string Name; + public XElement notNull; + public XElement isNull; + } + + [Test] + public void SerializeAndDeserializeNullableXml() + { + var xml = new NullableXml { Name = "test", notNull = XElement.Parse("test") }; + var json = JsonConvert.SerializeObject(xml); + + var w2 = JsonConvert.DeserializeObject(json); + Assert.AreEqual(xml.Name, w2.Name); + Assert.AreEqual(xml.isNull, w2.isNull); + Assert.AreEqual(xml.notNull.ToString(), w2.notNull.ToString()); + } +#endif } } #endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs index cb1fd690..64fcc7ed 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs @@ -368,7 +368,7 @@ namespace Newtonsoft.Json.Tests.Linq Assert.AreEqual("9223372036854775807", (string)(new JValue(new BigInteger(long.MaxValue)))); intData = (byte[]) (new JValue(new BigInteger(long.MaxValue))); - Assert.AreEqual(new byte[] { 255, 255, 255, 255, 255, 255, 255, 127 }, intData); + CollectionAssert.AreEqual(new byte[] { 255, 255, 255, 255, 255, 255, 255, 127 }, intData); #endif } diff --git a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs index b5155b54..be053098 100644 --- a/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs +++ b/Src/Newtonsoft.Json.Tests/Properties/AssemblyInfo.cs @@ -75,4 +75,4 @@ using System.Security; // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: [assembly: AssemblyVersion("4.5.0.0")] -[assembly: AssemblyFileVersion("5.0.1.15916")] +[assembly: AssemblyFileVersion("5.0.1.15917")] diff --git a/Src/Newtonsoft.Json.sln.DotSettings b/Src/Newtonsoft.Json.sln.DotSettings new file mode 100644 index 00000000..6a89a056 --- /dev/null +++ b/Src/Newtonsoft.Json.sln.DotSettings @@ -0,0 +1,5 @@ + + False + True + False + \ No newline at end of file diff --git a/Src/Newtonsoft.Json.vssettings b/Src/Newtonsoft.Json.vssettings new file mode 100644 index 00000000..8990c0c9 --- /dev/null +++ b/Src/Newtonsoft.Json.vssettings @@ -0,0 +1,13 @@ + + + + + + 2 + 2 + false + 2 + + + + \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs index 7d8322bc..682cbdd1 100644 --- a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs @@ -1082,6 +1082,9 @@ namespace Newtonsoft.Json.Converters /// The object value. public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { + if (reader.TokenType == JsonToken.Null) + return null; + XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable()); IXmlDocument document = null; IXmlNode rootNode = null; diff --git a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs index c601b7f3..2ce4f0e4 100644 --- a/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs +++ b/Src/Newtonsoft.Json/Properties/AssemblyInfo.cs @@ -90,6 +90,6 @@ using System.Security; // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: [assembly: AssemblyVersion("4.5.0.0")] -[assembly: AssemblyFileVersion("5.0.1.15916")] +[assembly: AssemblyFileVersion("5.0.1.15917")] [assembly: CLSCompliant(true)] diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs index 48872a7f..864e0229 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs @@ -547,11 +547,11 @@ namespace Newtonsoft.Json.Serialization private void ResolveCallbackMethods(JsonContract contract, Type t) { - List onSerializing; - List onSerialized; - List onDeserializing; - List onDeserialized; - List onError; + List onSerializing; + List onSerialized; + List onDeserializing; + List onDeserialized; + List onError; GetCallbackMethodsForType(t, out onSerializing, out onSerialized, out onDeserializing, out onDeserialized, out onError); @@ -559,34 +559,34 @@ namespace Newtonsoft.Json.Serialization { #if NETFX_CORE if (!t.IsGenericType() || (t.GetGenericTypeDefinition() != typeof(ConcurrentDictionary<,>))) - contract.OnSerializingMethods.AddRange(onSerializing); + contract.OnSerializingCallbacks.AddRange(onSerializing); #else - contract.OnSerializingMethods.AddRange(onSerializing); + contract.OnSerializingCallbacks.AddRange(onSerializing); #endif } if (onSerialized != null) - contract.OnSerializedMethods.AddRange(onSerialized); + contract.OnSerializedCallbacks.AddRange(onSerialized); if (onDeserializing != null) - contract.OnDeserializingMethods.AddRange(onDeserializing); + contract.OnDeserializingCallbacks.AddRange(onDeserializing); if (onDeserialized != null) { // ConcurrentDictionary throws an error here so don't use its OnDeserialized - http://json.codeplex.com/discussions/257093 #if !(NET35 || NET20 || SILVERLIGHT || WINDOWS_PHONE || PORTABLE) if (!t.IsGenericType() || (t.GetGenericTypeDefinition() != typeof(ConcurrentDictionary<,>))) - contract.OnDeserializedMethods.AddRange(onDeserialized); + contract.OnDeserializedCallbacks.AddRange(onDeserialized); #else - contract.OnDeserializedMethods.AddRange(onDeserialized); + contract.OnDeserializedCallbacks.AddRange(onDeserialized); #endif } if (onError != null) - contract.OnErrorMethods.AddRange(onError); + contract.OnErrorCallbacks.AddRange(onError); } - private void GetCallbackMethodsForType(Type type, out List onSerializing, out List onSerialized, out List onDeserializing, out List onDeserialized, out List onError) + private void GetCallbackMethodsForType(Type type, out List onSerializing, out List onSerialized, out List onDeserializing, out List onDeserialized, out List onError) { onSerializing = null; onSerialized = null; @@ -616,32 +616,32 @@ namespace Newtonsoft.Json.Serialization if (IsValidCallback(method, parameters, typeof(OnSerializingAttribute), currentOnSerializing, ref prevAttributeType)) { - onSerializing = onSerializing ?? new List(); - onSerializing.Add(method); + onSerializing = onSerializing ?? new List(); + onSerializing.Add(JsonContract.CreateSerializationCallback(method)); currentOnSerializing = method; } if (IsValidCallback(method, parameters, typeof(OnSerializedAttribute), currentOnSerialized, ref prevAttributeType)) { - onSerialized = onSerialized ?? new List(); - onSerialized.Add(method); + onSerialized = onSerialized ?? new List(); + onSerialized.Add(JsonContract.CreateSerializationCallback(method)); currentOnSerialized = method; } if (IsValidCallback(method, parameters, typeof(OnDeserializingAttribute), currentOnDeserializing, ref prevAttributeType)) { - onDeserializing = onDeserializing ?? new List(); - onDeserializing.Add(method); + onDeserializing = onDeserializing ?? new List(); + onDeserializing.Add(JsonContract.CreateSerializationCallback(method)); currentOnDeserializing = method; } if (IsValidCallback(method, parameters, typeof(OnDeserializedAttribute), currentOnDeserialized, ref prevAttributeType)) { - onDeserialized = onDeserialized ?? new List(); - onDeserialized.Add(method); + onDeserialized = onDeserialized ?? new List(); + onDeserialized.Add(JsonContract.CreateSerializationCallback(method)); currentOnDeserialized = method; } if (IsValidCallback(method, parameters, typeof(OnErrorAttribute), currentOnError, ref prevAttributeType)) { - onError = onError ?? new List(); - onError.Add(method); + onError = onError ?? new List(); + onError.Add(JsonContract.CreateSerializationErrorCallback(method)); currentOnError = method; } } diff --git a/Src/Newtonsoft.Json/Serialization/JsonContract.cs b/Src/Newtonsoft.Json/Serialization/JsonContract.cs index 04b97c59..e6d47030 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonContract.cs @@ -51,6 +51,10 @@ namespace Newtonsoft.Json.Serialization Linq } + public delegate void SerializationCallback(object o, StreamingContext context); + + public delegate void SerializationErrorCallback(object o, StreamingContext context, ErrorContext errorContext); + /// /// Contract details for a used by the . /// @@ -94,37 +98,44 @@ namespace Newtonsoft.Json.Serialization /// Gets or sets all methods called immediately after deserialization of the object. /// /// The methods called immediately after deserialization of the object. - public IList OnDeserializedMethods { get; private set; } + public IList OnDeserializedCallbacks { get; private set; } /// /// Gets or sets all methods called during deserialization of the object. /// /// The methods called during deserialization of the object. - public IList OnDeserializingMethods { get; private set; } + public IList OnDeserializingCallbacks { get; private set; } /// /// Gets or sets all methods called after serialization of the object graph. /// /// The methods called after serialization of the object graph. - public IList OnSerializedMethods { get; private set; } + public IList OnSerializedCallbacks { get; private set; } /// /// Gets or sets all methods called before serialization of the object. /// /// The methods called before serialization of the object. - public IList OnSerializingMethods { get; private set; } + public IList OnSerializingCallbacks { get; private set; } + + /// + /// Gets or sets all method called when an error is thrown during the serialization of the object. + /// + /// The methods called when an error is thrown during the serialization of the object. + public IList OnErrorCallbacks { get; private set; } /// /// Gets or sets the method called immediately after deserialization of the object. /// /// The method called immediately after deserialization of the object. + [Obsolete("This property is obsolete and has been replaced by the OnDeserializedCallbacks collection.")] public MethodInfo OnDeserialized { - get { return (OnDeserializedMethods.Count > 0) ? OnDeserializedMethods[0] : null; } - set + get { return (OnDeserializedCallbacks.Count > 0) ? OnDeserializedCallbacks[0].Method() : null; } + set { - OnDeserializedMethods.Clear(); - OnDeserializedMethods.Add(value); + OnDeserializedCallbacks.Clear(); + OnDeserializedCallbacks.Add(CreateSerializationCallback(value)); } } @@ -132,13 +143,14 @@ namespace Newtonsoft.Json.Serialization /// Gets or sets the method called during deserialization of the object. /// /// The method called during deserialization of the object. + [Obsolete("This property is obsolete and has been replaced by the OnDeserializingCallbacks collection.")] public MethodInfo OnDeserializing { - get { return (OnDeserializingMethods.Count > 0) ? OnDeserializingMethods[0] : null; } + get { return (OnDeserializingCallbacks.Count > 0) ? OnDeserializingCallbacks[0].Method() : null; } set { - OnDeserializingMethods.Clear(); - OnDeserializingMethods.Add(value); + OnDeserializingCallbacks.Clear(); + OnDeserializingCallbacks.Add(CreateSerializationCallback(value)); } } @@ -146,13 +158,14 @@ namespace Newtonsoft.Json.Serialization /// Gets or sets the method called after serialization of the object graph. /// /// The method called after serialization of the object graph. + [Obsolete("This property is obsolete and has been replaced by the OnSerializedCallbacks collection.")] public MethodInfo OnSerialized { - get { return (OnSerializedMethods.Count > 0) ? OnSerializedMethods[0] : null; } + get { return (OnSerializedCallbacks.Count > 0) ? OnSerializedCallbacks[0].Method() : null; } set { - OnSerializedMethods.Clear(); - OnSerializedMethods.Add(value); + OnSerializedCallbacks.Clear(); + OnSerializedCallbacks.Add(CreateSerializationCallback(value)); } } @@ -160,13 +173,29 @@ namespace Newtonsoft.Json.Serialization /// Gets or sets the method called before serialization of the object. /// /// The method called before serialization of the object. + [Obsolete("This property is obsolete and has been replaced by the OnSerializingCallbacks collection.")] public MethodInfo OnSerializing { - get { return (OnSerializingMethods.Count > 0) ? OnSerializingMethods[0] : null; } + get { return (OnSerializingCallbacks.Count > 0) ? OnSerializingCallbacks[0].Method() : null; } set { - OnSerializingMethods.Clear(); - OnSerializingMethods.Add(value); + OnSerializingCallbacks.Clear(); + OnSerializingCallbacks.Add(CreateSerializationCallback(value)); + } + } + + /// + /// Gets or sets the method called when an error is thrown during the serialization of the object. + /// + /// The method called when an error is thrown during the serialization of the object. + [Obsolete("This property is obsolete and has been replaced by the OnErrorCallbacks collection.")] + public MethodInfo OnError + { + get { return (OnErrorCallbacks.Count > 0) ? OnErrorCallbacks[0].Method() : null; } + set + { + OnErrorCallbacks.Clear(); + OnErrorCallbacks.Add(CreateSerializationErrorCallback(value)); } } @@ -182,66 +211,6 @@ namespace Newtonsoft.Json.Serialization /// true if the default object creator is non-public; otherwise, false. public bool DefaultCreatorNonPublic { get; set; } - /// - /// Gets or sets all method called when an error is thrown during the serialization of the object. - /// - /// The methods called when an error is thrown during the serialization of the object. - public IList OnErrorMethods { get; private set; } - - /// - /// Gets or sets the method called when an error is thrown during the serialization of the object. - /// - /// The method called when an error is thrown during the serialization of the object. - public MethodInfo OnError - { - get { return (OnErrorMethods.Count > 0) ? OnErrorMethods[0] : null; } - set - { - OnErrorMethods.Clear(); - OnErrorMethods.Add(value); - } - } - - internal void InvokeOnSerializing(object o, StreamingContext context) - { - foreach (MethodInfo mi in OnSerializingMethods) - { - mi.Invoke(o, new object[] {context}); - } - } - - internal void InvokeOnSerialized(object o, StreamingContext context) - { - foreach (MethodInfo mi in OnSerializedMethods) - { - mi.Invoke(o, new object[] {context}); - } - } - - internal void InvokeOnDeserializing(object o, StreamingContext context) - { - foreach (MethodInfo mi in OnDeserializingMethods) - { - mi.Invoke(o, new object[] {context}); - } - } - - internal void InvokeOnDeserialized(object o, StreamingContext context) - { - foreach (MethodInfo mi in OnDeserializedMethods) - { - mi.Invoke(o, new object[] {context}); - } - } - - internal void InvokeOnError(object o, StreamingContext context, ErrorContext errorContext) - { - foreach (MethodInfo mi in OnErrorMethods) - { - mi.Invoke(o, new object[] {context, errorContext}); - } - } - internal JsonContract(Type underlyingType) { ValidationUtils.ArgumentNotNull(underlyingType, "underlyingType"); @@ -286,11 +255,61 @@ namespace Newtonsoft.Json.Serialization InternalReadType = ReadType.Read; } - OnErrorMethods = new List(); - OnSerializedMethods = new List(); - OnSerializingMethods = new List(); - OnDeserializedMethods = new List(); - OnDeserializingMethods = new List(); + OnErrorCallbacks = new List(); + OnSerializedCallbacks = new List(); + OnSerializingCallbacks = new List(); + OnDeserializedCallbacks = new List(); + OnDeserializingCallbacks = new List(); + } + + internal void InvokeOnSerializing(object o, StreamingContext context) + { + foreach (SerializationCallback callback in OnSerializingCallbacks) + { + callback(o, context); + } + } + + internal void InvokeOnSerialized(object o, StreamingContext context) + { + foreach (SerializationCallback callback in OnSerializedCallbacks) + { + callback(o, context); + } + } + + internal void InvokeOnDeserializing(object o, StreamingContext context) + { + foreach (SerializationCallback callback in OnDeserializingCallbacks) + { + callback(o, context); + } + } + + internal void InvokeOnDeserialized(object o, StreamingContext context) + { + foreach (SerializationCallback callback in OnDeserializedCallbacks) + { + callback(o, context); + } + } + + internal void InvokeOnError(object o, StreamingContext context, ErrorContext errorContext) + { + foreach (SerializationErrorCallback callback in OnErrorCallbacks) + { + callback(o, context, errorContext); + } + } + + internal static SerializationCallback CreateSerializationCallback(MethodInfo callbackMethodInfo) + { + return (o, context) => callbackMethodInfo.Invoke(o, new object[] { context }); + } + + internal static SerializationErrorCallback CreateSerializationErrorCallback(MethodInfo callbackMethodInfo) + { + return (o, context, econtext) => callbackMethodInfo.Invoke(o, new object[] { context, econtext }); } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs b/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs index 47619d94..b0062ae2 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs @@ -168,6 +168,6 @@ namespace Newtonsoft.Json.Serialization } #endif - public bool IsReadOnlyDictionary { get; set; } + internal bool IsReadOnlyDictionary { get; set; } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index 1460e10e..6a14fde7 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -578,10 +578,10 @@ To fix this error either change the JSON to a {1} or change the deserialized typ if (id != null && isTemporaryListReference) throw JsonSerializationException.Create(reader, "Cannot preserve reference to array or readonly list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)); - if (contract.OnSerializingMethods.Count > 0 && isTemporaryListReference) + if (contract.OnSerializingCallbacks.Count > 0 && isTemporaryListReference) throw JsonSerializationException.Create(reader, "Cannot call OnSerializing on an array or readonly list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)); - if (contract.OnErrorMethods.Count > 0 && isTemporaryListReference) + if (contract.OnErrorCallbacks.Count > 0 && isTemporaryListReference) throw JsonSerializationException.Create(reader, "Cannot call OnError on an array or readonly list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)); if (!arrayContract.IsMultidimensionalArray) diff --git a/Src/Newtonsoft.Json/Utilities/TypeExtensions.cs b/Src/Newtonsoft.Json/Utilities/TypeExtensions.cs index e2a3ab8c..5d92f745 100644 --- a/Src/Newtonsoft.Json/Utilities/TypeExtensions.cs +++ b/Src/Newtonsoft.Json/Utilities/TypeExtensions.cs @@ -78,6 +78,15 @@ namespace Newtonsoft.Json.Utilities } #endif + public static MethodInfo Method(this Delegate d) + { +#if NETFX_CORE + return d.GetMethodInfo(); +#else + return d.Method; +#endif + } + public static MemberTypes MemberType(this MemberInfo memberInfo) { #if !(NETFX_CORE || PORTABLE)