Skip to content

Commit

Permalink
-Fixed error when deserializing large JSON integers to XML
Browse files Browse the repository at this point in the history
-Fixed serializing extension data properties with no setter
  • Loading branch information
JamesNK committed Mar 15, 2015
1 parent 502c01b commit cdac4d8
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 4 deletions.
16 changes: 16 additions & 0 deletions Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2338,6 +2338,22 @@ public void SerializeAndDeserializeXmlElementWithNamespaceInChildrenRootDontHave

Assert.AreEqual(@"<root><b xmlns=""http://www.example.com/ns"">Asd</b><c>AAA</c><test>adad</test></root>", xmlBack.OuterXml);
}

#if !(NET20 || NET35 || PORTABLE || PORTABLE40)
[Test]
public void DeserializeBigInteger()
{
var json = "{\"DocumentId\":13779965364495889899 }";

XmlDocument node = JsonConvert.DeserializeXmlNode(json);

Assert.AreEqual("<DocumentId>13779965364495889899</DocumentId>", node.OuterXml);

string json2 = JsonConvert.SerializeXmlNode(node);

Assert.AreEqual(@"{""DocumentId"":""13779965364495889899""}", json2);
}
#endif
}
}
#endif
89 changes: 87 additions & 2 deletions Src/Newtonsoft.Json.Tests/Serialization/ExtensionDataTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public class ExtensionDataTests : TestFixtureBase
public class CustomDictionary : IDictionary<string, object>
{
private readonly IDictionary<string, object> _inner = new Dictionary<string, object>();

public void Add(string key, object value)
{
_inner.Add(key, value);
Expand Down Expand Up @@ -235,7 +235,7 @@ public void ExtensionDataFloatParseHandling()
}

#pragma warning disable 649
class ExtendedObject
private class ExtendedObject
{
[JsonExtensionData]
internal IDictionary<string, JToken> _additionalData;
Expand Down Expand Up @@ -744,5 +744,90 @@ public void DeserializeNullableProperty()
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<DocNoSetter>(@"{""_name"":""documentName""}");

Assert.AreEqual("documentName", doc.Name);
}

[Test]
public void DeserializeExtensionData_NoSetterAndWithExtensionData()
{
try
{
JsonConvert.DeserializeObject<DocNoSetter>(@"{""_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<JsonException>(
() =>
{
JsonConvert.SerializeObject(new DocNoGetter());
},
"Invalid extension data attribute on 'Newtonsoft.Json.Tests.Serialization.ExtensionDataTests+DocNoGetter'. Member 'Content' must have a getter.");
}
}
}
6 changes: 6 additions & 0 deletions Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
// OTHER DEALINGS IN THE SOFTWARE.
#endregion

using System.Numerics;
#if !PORTABLE40
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -1417,6 +1418,11 @@ private string ConvertTokenToXmlValue(JsonReader reader)
}
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)
Expand Down
13 changes: 11 additions & 2 deletions Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

using System;
using System.Collections;
using Newtonsoft.Json.Schema;
#if !(NET35 || NET20 || PORTABLE || PORTABLE40)
using System.Collections.Concurrent;
#endif
Expand Down Expand Up @@ -438,6 +439,9 @@ private MemberInfo GetExtensionDataMemberForType(Type type)
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;
Expand Down Expand Up @@ -479,17 +483,22 @@ private static void SetExtensionDataDelegates(JsonObjectContract contract, Membe
else
createdType = t;

MethodInfo addMethod = t.GetMethod("Add", new[] { keyType, valueType });
Func<object, object> getExtensionDataDictionary = JsonTypeReflector.ReflectionDelegateFactory.CreateGet<object>(member);
Action<object, object> setExtensionDataDictionary = JsonTypeReflector.ReflectionDelegateFactory.CreateSet<object>(member);
Action<object, object> setExtensionDataDictionary = (ReflectionUtils.CanSetMemberValue(member, true, false))
? JsonTypeReflector.ReflectionDelegateFactory.CreateSet<object>(member)
: null;
Func<object> createExtensionDataDictionary = JsonTypeReflector.ReflectionDelegateFactory.CreateDefaultConstructor<object>(createdType);
MethodInfo addMethod = t.GetMethod("Add", new[] { keyType, valueType });
MethodCall<object, object> setExtensionDataDictionaryValue = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(addMethod);

ExtensionDataSetter extensionDataSetter = (o, key, value) =>
{
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);
}
Expand Down

0 comments on commit cdac4d8

Please sign in to comment.