From cdac4d8d386da2ae2e11164f575e29ef31d98c1b Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Sun, 15 Mar 2015 18:45:29 +1300 Subject: [PATCH] -Fixed error when deserializing large JSON integers to XML -Fixed serializing extension data properties with no setter --- .../Converters/XmlNodeConverterTest.cs | 16 ++++ .../Serialization/ExtensionDataTests.cs | 89 ++++++++++++++++++- .../Converters/XmlNodeConverter.cs | 6 ++ .../Serialization/DefaultContractResolver.cs | 13 ++- 4 files changed, 120 insertions(+), 4 deletions(-) diff --git a/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs index 8df81e94..58d87a54 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs @@ -2338,6 +2338,22 @@ namespace Newtonsoft.Json.Tests.Converters Assert.AreEqual(@"AsdAAAadad", xmlBack.OuterXml); } + +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) + [Test] + public void DeserializeBigInteger() + { + var json = "{\"DocumentId\":13779965364495889899 }"; + + XmlDocument node = JsonConvert.DeserializeXmlNode(json); + + Assert.AreEqual("13779965364495889899", node.OuterXml); + + string json2 = JsonConvert.SerializeXmlNode(node); + + Assert.AreEqual(@"{""DocumentId"":""13779965364495889899""}", json2); + } +#endif } } #endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Serialization/ExtensionDataTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/ExtensionDataTests.cs index 4da7c9a2..512e07e7 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/ExtensionDataTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/ExtensionDataTests.cs @@ -48,7 +48,7 @@ namespace Newtonsoft.Json.Tests.Serialization public class CustomDictionary : IDictionary { private readonly IDictionary _inner = new Dictionary(); - + public void Add(string key, object value) { _inner.Add(key, value); @@ -235,7 +235,7 @@ namespace Newtonsoft.Json.Tests.Serialization } #pragma warning disable 649 - class ExtendedObject + private class ExtendedObject { [JsonExtensionData] internal IDictionary _additionalData; @@ -744,5 +744,90 @@ namespace Newtonsoft.Json.Tests.Serialization Assert.AreEqual(1, c.CustomFields.Count); Assert.AreEqual("Testing", (string)c.CustomFields["CustomField1"]); } + + public class DocNoSetter + { + private readonly JObject _content; + + public DocNoSetter() + { + } + + public DocNoSetter(JObject content) + { + _content = content; + } + + [JsonProperty("_name")] + public string Name { get; set; } + + [JsonExtensionData] + public JObject Content + { + get { return _content; } + } + } + + [Test] + public void SerializeExtensionData_NoSetter() + { + string json = JsonConvert.SerializeObject(new DocNoSetter(new JObject(new JProperty("Property1", 123))) + { + Name = "documentName" + }); + Assert.AreEqual(@"{""_name"":""documentName"",""Property1"":123}", json); + } + + [Test] + public void SerializeExtensionData_NoSetterAndNoValue() + { + string json = JsonConvert.SerializeObject(new DocNoSetter(null) + { + Name = "documentName" + }); + Assert.AreEqual(@"{""_name"":""documentName""}", json); + } + + [Test] + public void DeserializeExtensionData_NoSetterAndNoExtensionData() + { + DocNoSetter doc = JsonConvert.DeserializeObject(@"{""_name"":""documentName""}"); + + Assert.AreEqual("documentName", doc.Name); + } + + [Test] + public void DeserializeExtensionData_NoSetterAndWithExtensionData() + { + try + { + JsonConvert.DeserializeObject(@"{""_name"":""documentName"",""Property1"":123}"); + } + catch (JsonSerializationException ex) + { + Assert.AreEqual("Error setting value in extension data for type 'Newtonsoft.Json.Tests.Serialization.ExtensionDataTests+DocNoSetter'. Path 'Property1', line 1, position 39.", ex.Message); + Assert.AreEqual("Cannot set value onto extension data member 'Content'. The extension data collection is null and it cannot be set.", ex.InnerException.Message); + } + } + + public class DocNoGetter + { + [JsonExtensionData] + public JObject Content + { + set { } + } + } + + [Test] + public void SerializeExtensionData_NoGetter() + { + ExceptionAssert.Throws( + () => + { + JsonConvert.SerializeObject(new DocNoGetter()); + }, + "Invalid extension data attribute on 'Newtonsoft.Json.Tests.Serialization.ExtensionDataTests+DocNoGetter'. Member 'Content' must have a getter."); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs index 9607d6a0..aa47cffa 100644 --- a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs @@ -23,6 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion +using System.Numerics; #if !PORTABLE40 using System; using System.Collections.Generic; @@ -1417,6 +1418,11 @@ namespace Newtonsoft.Json.Converters } else if (reader.TokenType == JsonToken.Integer) { +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) + if (reader.Value is BigInteger) + return ((BigInteger)reader.Value).ToString(CultureInfo.InvariantCulture); +#endif + return XmlConvert.ToString(Convert.ToInt64(reader.Value, CultureInfo.InvariantCulture)); } else if (reader.TokenType == JsonToken.Float) diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs index 797bfa52..7a67ecc6 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs @@ -25,6 +25,7 @@ using System; using System.Collections; +using Newtonsoft.Json.Schema; #if !(NET35 || NET20 || PORTABLE || PORTABLE40) using System.Collections.Concurrent; #endif @@ -438,6 +439,9 @@ namespace Newtonsoft.Json.Serialization if (!m.IsDefined(typeof(JsonExtensionDataAttribute), false)) return false; + if (!ReflectionUtils.CanReadMemberValue(m, true)) + throw new JsonException("Invalid extension data attribute on '{0}'. Member '{1}' must have a getter.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(m.DeclaringType), m.Name)); + Type t = ReflectionUtils.GetMemberUnderlyingType(m); Type dictionaryType; @@ -479,10 +483,12 @@ namespace Newtonsoft.Json.Serialization else createdType = t; - MethodInfo addMethod = t.GetMethod("Add", new[] { keyType, valueType }); Func getExtensionDataDictionary = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(member); - Action setExtensionDataDictionary = JsonTypeReflector.ReflectionDelegateFactory.CreateSet(member); + Action setExtensionDataDictionary = (ReflectionUtils.CanSetMemberValue(member, true, false)) + ? JsonTypeReflector.ReflectionDelegateFactory.CreateSet(member) + : null; Func createExtensionDataDictionary = JsonTypeReflector.ReflectionDelegateFactory.CreateDefaultConstructor(createdType); + MethodInfo addMethod = t.GetMethod("Add", new[] { keyType, valueType }); MethodCall setExtensionDataDictionaryValue = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(addMethod); ExtensionDataSetter extensionDataSetter = (o, key, value) => @@ -490,6 +496,9 @@ namespace Newtonsoft.Json.Serialization object dictionary = getExtensionDataDictionary(o); if (dictionary == null) { + if (setExtensionDataDictionary == null) + throw new JsonSerializationException("Cannot set value onto extension data member '{0}'. The extension data collection is null and it cannot be set.".FormatWith(CultureInfo.InvariantCulture, member.Name)); + dictionary = createExtensionDataDictionary(); setExtensionDataDictionary(o, dictionary); }