-Fix occasional error when converting non-long integer properties to XML

-Fix boolean values sometimes being capitalized when converting to XML
-Fix error when deserializing ConcurrentDictionary
-Fix serializing some Uris
-Change KeyValurPairConverter to not rely on the order of the key and value properties
This commit is contained in:
JamesNK
2011-10-31 23:44:10 +00:00
parent b24bcda921
commit b305ba100b
12 changed files with 327 additions and 46 deletions
@@ -1,4 +1,4 @@
#region License
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
@@ -1257,6 +1257,50 @@ namespace Newtonsoft.Json.Tests.Converters
}
}", json);
}
[Test]
public void DeserializeNonInt64IntegerValues()
{
var dict = new Dictionary<string, object> { { "Int16", (short)1 }, { "Float", 2f }, { "Int32", 3 } };
var obj = JObject.FromObject(dict);
var serializer = JsonSerializer.Create(new JsonSerializerSettings { Converters = { new XmlNodeConverter() { DeserializeRootElementName = "root" } } });
using (var reader = obj.CreateReader())
{
var value = (XmlDocument)serializer.Deserialize(reader, typeof(XmlDocument));
Assert.AreEqual(@"<root><Int16>1</Int16><Float>2</Float><Int32>3</Int32></root>", value.InnerXml);
}
}
[Test]
public void DeserializingBooleanValues()
{
MemoryStream ms = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(@"{root:{""@booleanType"":true}}"));
MemoryStream xml = new MemoryStream();
JsonBodyToSoapXml(ms, xml);
string xmlString = System.Text.Encoding.UTF8.GetString(xml.ToArray());
Assert.AreEqual(@"<?xml version=""1.0"" encoding=""utf-8""?><root booleanType=""true"" />", xmlString);
}
static void JsonBodyToSoapXml(Stream json, Stream xml)
{
Newtonsoft.Json.JsonSerializerSettings settings = new Newtonsoft.Json.JsonSerializerSettings();
settings.Converters.Add(new Newtonsoft.Json.Converters.XmlNodeConverter());
Newtonsoft.Json.JsonSerializer serializer = Newtonsoft.Json.JsonSerializer.Create(settings);
using (Newtonsoft.Json.JsonTextReader reader = new Newtonsoft.Json.JsonTextReader(new System.IO.StreamReader(json)))
{
XmlDocument doc = (XmlDocument)serializer.Deserialize(reader, typeof(XmlDocument));
if (reader.Read() && reader.TokenType != JsonToken.Comment)
throw new JsonSerializationException("Additional text found in JSON string after finishing deserializing object.");
using (XmlWriter writer = XmlWriter.Create(xml))
{
doc.Save(writer);
}
}
}
}
}
#endif
@@ -436,5 +436,17 @@ Parameter name: index")]
{
JArray.Parse("[1");
}
[Test]
public void InsertAddEnd()
{
JArray array = new JArray();
array.Insert(0, 123);
array.Insert(1, 456);
Assert.AreEqual(2, array.Count);
Assert.AreEqual(123, (int)array[0]);
Assert.AreEqual(456, (int)array[1]);
}
}
}
@@ -209,6 +209,9 @@ namespace Newtonsoft.Json.Tests.Linq
[Test]
public void Casting()
{
Assert.AreEqual(1L, (long)(new JValue(1)));
Assert.AreEqual(2L, (long) new JArray(1, 2, 3)[1]);
Assert.AreEqual(new DateTime(2000, 12, 20), (DateTime)new JValue(new DateTime(2000, 12, 20)));
#if !PocketPC && !NET20
Assert.AreEqual(new DateTimeOffset(2000, 12, 20, 23, 50, 10, TimeSpan.Zero), (DateTimeOffset)new JValue(new DateTimeOffset(2000, 12, 20, 23, 50, 10, TimeSpan.Zero)));
@@ -126,14 +126,14 @@ namespace Newtonsoft.Json.Tests
public void BuildJObject()
{
JObject o = new JObject();
for (int i = 0; i < 200; i++)
for (int i = 0; i < 50; i++)
{
o[i.ToString()] = i;
}
string jsonText = o.ToString();
// this is extremely slow with 5000 interations
int interations = 100;
int interations = 1000;
TimeOperation(() =>
{
@@ -66,5 +66,5 @@ using System.Runtime.InteropServices;
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.0.3.0")]
#if !PocketPC
[assembly: AssemblyFileVersion("4.0.3.14202")]
[assembly: AssemblyFileVersion("4.0.3.14301")]
#endif
@@ -24,11 +24,15 @@
#endregion
using System;
#if !(NET35 || NET20 || SILVERLIGHT || WINDOWS_PHONE)
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
#if !SILVERLIGHT && !PocketPC && !NET20
using System.ComponentModel.DataAnnotations;
using System.Configuration;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization.Formatters;
using System.Threading;
using System.Web.Script.Serialization;
#endif
@@ -4910,6 +4914,107 @@ keyword such as type of business.""
Assert.AreEqual(@"{""p"":1}", result);
}
}
#if !(NET35 || NET20 || SILVERLIGHT || WINDOWS_PHONE)
[Test]
public void DeserializeConcurrentDictionary()
{
IDictionary<string, Component> components = new Dictionary<string, Component>
{
{"Key!", new Component()}
};
GameObject go = new GameObject
{
Components = new ConcurrentDictionary<string, Component>(components),
Id = "Id!",
Name = "Name!"
};
string originalJson = JsonConvert.SerializeObject(go, Formatting.Indented);
Assert.AreEqual(@"{
""Components"": {
""Key!"": {}
},
""Id"": ""Id!"",
""Name"": ""Name!""
}", originalJson);
GameObject newObject = JsonConvert.DeserializeObject<GameObject>(originalJson);
Assert.AreEqual(1, newObject.Components.Count);
Assert.AreEqual("Id!", newObject.Id);
Assert.AreEqual("Name!", newObject.Name);
}
#endif
[Test]
public void DeserializeKeyValuePairArray()
{
string json = @"[ { ""Value"": [ ""1"", ""2"" ], ""Key"": ""aaa"", ""BadContent"": [ 0 ] }, { ""Value"": [ ""3"", ""4"" ], ""Key"": ""bbb"" } ]";
IList<KeyValuePair<string, IList<string>>> values = JsonConvert.DeserializeObject<IList<KeyValuePair<string, IList<string>>>>(json);
Assert.AreEqual(2, values.Count);
Assert.AreEqual("aaa", values[0].Key);
Assert.AreEqual(2, values[0].Value.Count);
Assert.AreEqual("1", values[0].Value[0]);
Assert.AreEqual("2", values[0].Value[1]);
Assert.AreEqual("bbb", values[1].Key);
Assert.AreEqual(2, values[1].Value.Count);
Assert.AreEqual("3", values[1].Value[0]);
Assert.AreEqual("4", values[1].Value[1]);
}
[Test]
public void DeserializeNullableKeyValuePairArray()
{
string json = @"[ { ""Value"": [ ""1"", ""2"" ], ""Key"": ""aaa"", ""BadContent"": [ 0 ] }, null, { ""Value"": [ ""3"", ""4"" ], ""Key"": ""bbb"" } ]";
IList<KeyValuePair<string, IList<string>>?> values = JsonConvert.DeserializeObject<IList<KeyValuePair<string, IList<string>>?>>(json);
Assert.AreEqual(3, values.Count);
Assert.AreEqual("aaa", values[0].Value.Key);
Assert.AreEqual(2, values[0].Value.Value.Count);
Assert.AreEqual("1", values[0].Value.Value[0]);
Assert.AreEqual("2", values[0].Value.Value[1]);
Assert.AreEqual(null, values[1]);
Assert.AreEqual("bbb", values[2].Value.Key);
Assert.AreEqual(2, values[2].Value.Value.Count);
Assert.AreEqual("3", values[2].Value.Value[0]);
Assert.AreEqual("4", values[2].Value.Value[1]);
}
[Test]
[ExpectedException(typeof (Exception), ExpectedMessage = "Could not deserialize Null to KeyValuePair.")]
public void DeserializeNullToNonNullableKeyValuePairArray()
{
string json = @"[ null ]";
JsonConvert.DeserializeObject<IList<KeyValuePair<string, IList<string>>>>(json);
}
[Test]
public void SerializeUriWithQuotes()
{
string input = "http://test.com/%22foo+bar%22";
Uri uri = new Uri(input);
string json = JsonConvert.SerializeObject(uri);
Uri output = JsonConvert.DeserializeObject<Uri>(json);
Assert.AreEqual(uri, output);
}
[Test]
public void SerializeUriWithSlashes()
{
string input = @"http://tes/?a=b\\c&d=e\";
Uri uri = new Uri(input);
string json = JsonConvert.SerializeObject(uri);
Uri output = JsonConvert.DeserializeObject<Uri>(json);
Assert.AreEqual(uri, output);
}
}
public class UriGuidTimeSpanTestClass
@@ -4920,4 +5025,47 @@ keyword such as type of business.""
public TimeSpan? NullableTimeSpan { get; set; }
public Uri Uri { get; set; }
}
#if !(NET35 || NET20 || SILVERLIGHT || WINDOWS_PHONE)
[JsonObject(MemberSerialization.OptIn)]
public class GameObject
{
[JsonProperty]
public string Id { get; set; }
[JsonProperty]
public string Name { get; set; }
[JsonProperty]
public ConcurrentDictionary<string, Component> Components;
public GameObject()
{
Components = new ConcurrentDictionary<string, Component>();
}
}
[JsonObject(MemberSerialization.OptIn)]
public class Component
{
[JsonIgnore] // Ignore circular reference
public GameObject GameObject { get; set; }
public Component()
{
}
}
[JsonObject(MemberSerialization.OptIn)]
public class TestComponent : Component
{
[JsonProperty]
public int MyProperty { get; set; }
public TestComponent()
{
}
}
#endif
}
@@ -42,19 +42,50 @@ namespace Newtonsoft.Json.Converters
/// <returns>The object value.</returns>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
IList<Type> genericArguments = objectType.GetGenericArguments();
bool isNullable = ReflectionUtils.IsNullableType(objectType);
if (reader.TokenType == JsonToken.Null)
{
if (!isNullable)
throw new Exception("Could not deserialize Null to KeyValuePair.");
return null;
}
Type t = (isNullable)
? Nullable.GetUnderlyingType(objectType)
: objectType;
IList<Type> genericArguments = t.GetGenericArguments();
Type keyType = genericArguments[0];
Type valueType = genericArguments[1];
reader.Read();
reader.Read();
object key = serializer.Deserialize(reader, keyType);
reader.Read();
reader.Read();
object value = serializer.Deserialize(reader, valueType);
object key = null;
object value = null;
reader.Read();
return ReflectionUtils.CreateInstance(objectType, key, value);
while (reader.TokenType == JsonToken.PropertyName)
{
switch (reader.Value.ToString())
{
case "Key":
reader.Read();
key = serializer.Deserialize(reader, keyType);
break;
case "Value":
reader.Read();
value = serializer.Deserialize(reader, valueType);
break;
default:
reader.Skip();
break;
}
reader.Read();
}
return ReflectionUtils.CreateInstance(t, key, value);
}
/// <summary>
@@ -66,8 +97,12 @@ namespace Newtonsoft.Json.Converters
/// </returns>
public override bool CanConvert(Type objectType)
{
if (objectType.IsValueType && objectType.IsGenericType)
return (objectType.GetGenericTypeDefinition() == typeof (KeyValuePair<,>));
Type t = (ReflectionUtils.IsNullableType(objectType))
? Nullable.GetUnderlyingType(objectType)
: objectType;
if (t.IsValueType && t.IsGenericType)
return (t.GetGenericTypeDefinition() == typeof(KeyValuePair<,>));
return false;
}
@@ -26,6 +26,7 @@
#if !SILVERLIGHT || WINDOWS_PHONE
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Xml;
#if !NET20
using System.Xml.Linq;
@@ -1194,26 +1195,13 @@ namespace Newtonsoft.Json.Converters
element.SetAttributeNode(attribute);
}
if (reader.TokenType == JsonToken.String)
if (reader.TokenType == JsonToken.String
|| reader.TokenType == JsonToken.Integer
|| reader.TokenType == JsonToken.Float
|| reader.TokenType == JsonToken.Boolean
|| reader.TokenType == JsonToken.Date)
{
element.AppendChild(document.CreateTextNode(reader.Value.ToString()));
}
else if (reader.TokenType == JsonToken.Integer)
{
element.AppendChild(document.CreateTextNode(XmlConvert.ToString((long)reader.Value)));
}
else if (reader.TokenType == JsonToken.Float)
{
element.AppendChild(document.CreateTextNode(XmlConvert.ToString((double)reader.Value)));
}
else if (reader.TokenType == JsonToken.Boolean)
{
element.AppendChild(document.CreateTextNode(XmlConvert.ToString((bool)reader.Value)));
}
else if (reader.TokenType == JsonToken.Date)
{
DateTime d = (DateTime)reader.Value;
element.AppendChild(document.CreateTextNode(XmlConvert.ToString(d, DateTimeUtils.ToSerializationMode(d.Kind))));
element.AppendChild(document.CreateTextNode(ConvertTokenToXmlValue(reader)));
}
else if (reader.TokenType == JsonToken.Null)
{
@@ -1233,6 +1221,39 @@ namespace Newtonsoft.Json.Converters
}
}
private string ConvertTokenToXmlValue(JsonReader reader)
{
if (reader.TokenType == JsonToken.String)
{
return reader.Value.ToString();
}
else if (reader.TokenType == JsonToken.Integer)
{
return XmlConvert.ToString(Convert.ToInt64(reader.Value, CultureInfo.InvariantCulture));
}
else if (reader.TokenType == JsonToken.Float)
{
return XmlConvert.ToString(Convert.ToDouble(reader.Value, CultureInfo.InvariantCulture));
}
else if (reader.TokenType == JsonToken.Boolean)
{
return XmlConvert.ToString(Convert.ToBoolean(reader.Value, CultureInfo.InvariantCulture));
}
else if (reader.TokenType == JsonToken.Date)
{
DateTime d = Convert.ToDateTime(reader.Value, CultureInfo.InvariantCulture);
return XmlConvert.ToString(d, DateTimeUtils.ToSerializationMode(d.Kind));
}
else if (reader.TokenType == JsonToken.Null)
{
return null;
}
else
{
throw new Exception("Cannot get an XML string value from token type '{0}'.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
}
}
private void ReadArrayElements(JsonReader reader, IXmlDocument document, string propertyName, IXmlNode currentNode, XmlNamespaceManager manager)
{
string elementPrefix = MiscellaneousUtils.GetPrefix(propertyName);
@@ -1309,7 +1330,7 @@ namespace Newtonsoft.Json.Converters
case '@':
attributeName = attributeName.Substring(1);
reader.Read();
attributeValue = reader.Value.ToString();
attributeValue = ConvertTokenToXmlValue(reader);
attributeNameValues.Add(attributeName, attributeValue);
string namespacePrefix;
+4 -1
View File
@@ -392,7 +392,10 @@ namespace Newtonsoft.Json
/// <returns>A JSON string representation of the <see cref="Uri"/>.</returns>
public static string ToString(Uri value)
{
return '"' + value.ToString() + '"';
if (value == null)
return Null;
return ToString(value.ToString());
}
/// <summary>
+10 -10
View File
@@ -418,7 +418,7 @@ namespace Newtonsoft.Json.Linq
if (v == null || !ValidateBoolean(v, false))
throw new ArgumentException("Can not convert {0} to Boolean.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
return (bool)v.Value;
return Convert.ToBoolean(v.Value, CultureInfo.InvariantCulture);
}
#if !PocketPC && !NET20
@@ -451,7 +451,7 @@ namespace Newtonsoft.Json.Linq
if (v == null || !ValidateBoolean(v, true))
throw new ArgumentException("Can not convert {0} to Boolean.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
return (bool?)v.Value;
return (v.Value != null) ? (bool?)Convert.ToBoolean(v.Value, CultureInfo.InvariantCulture) : null;
}
/// <summary>
@@ -465,7 +465,7 @@ namespace Newtonsoft.Json.Linq
if (v == null || !ValidateInteger(v, false))
throw new ArgumentException("Can not convert {0} to Int64.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
return (long)v.Value;
return Convert.ToInt64(v.Value, CultureInfo.InvariantCulture);
}
/// <summary>
@@ -482,7 +482,7 @@ namespace Newtonsoft.Json.Linq
if (v == null || !ValidateDate(v, true))
throw new ArgumentException("Can not convert {0} to DateTime.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
return (DateTime?)v.Value;
return (v.Value != null) ? (DateTime?)Convert.ToDateTime(v.Value, CultureInfo.InvariantCulture) : null;
}
#if !PocketPC && !NET20
@@ -644,7 +644,7 @@ namespace Newtonsoft.Json.Linq
if (v == null || !ValidateDate(v, false))
throw new ArgumentException("Can not convert {0} to DateTime.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
return (DateTime)v.Value;
return Convert.ToDateTime(v.Value, CultureInfo.InvariantCulture);
}
/// <summary>
@@ -661,7 +661,7 @@ namespace Newtonsoft.Json.Linq
if (v == null || !ValidateInteger(v, true))
throw new ArgumentException("Can not convert {0} to Int64.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
return (long?)v.Value;
return (v.Value != null) ? (long?)Convert.ToInt64(v.Value, CultureInfo.InvariantCulture) : null;
}
/// <summary>
@@ -710,7 +710,7 @@ namespace Newtonsoft.Json.Linq
if (v == null || !ValidateInteger(v, true))
throw new ArgumentException("Can not convert {0} to UInt32.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
return (uint?)v.Value;
return (v.Value != null) ? (uint?)Convert.ToUInt32(v.Value, CultureInfo.InvariantCulture) : null;
}
/// <summary>
@@ -728,7 +728,7 @@ namespace Newtonsoft.Json.Linq
if (v == null || !ValidateInteger(v, true))
throw new ArgumentException("Can not convert {0} to UInt64.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
return (ulong?)v.Value;
return (v.Value != null) ? (ulong?)Convert.ToUInt64(v.Value, CultureInfo.InvariantCulture) : null;
}
/// <summary>
@@ -742,7 +742,7 @@ namespace Newtonsoft.Json.Linq
if (v == null || !ValidateFloat(v, false))
throw new ArgumentException("Can not convert {0} to Double.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
return (double)v.Value;
return Convert.ToDouble(v.Value, CultureInfo.InvariantCulture);
}
/// <summary>
@@ -773,7 +773,7 @@ namespace Newtonsoft.Json.Linq
if (v == null || !ValidateString(v))
throw new ArgumentException("Can not convert {0} to String.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
return (string)v.Value;
return (v.Value != null) ? Convert.ToString(v.Value) : null;
}
/// <summary>
@@ -85,7 +85,7 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("4.0.3.0")]
#if !PocketPC
[assembly: AssemblyFileVersion("4.0.3.14202")]
[assembly: AssemblyFileVersion("4.0.3.14301")]
#endif
[assembly: CLSCompliant(true)]
@@ -25,6 +25,9 @@
using System;
using System.Collections;
#if !(NET35 || NET20 || SILVERLIGHT || WINDOWS_PHONE)
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.ComponentModel;
#if !(NET35 || NET20 || WINDOWS_PHONE)
@@ -463,12 +466,24 @@ namespace Newtonsoft.Json.Serialization
if (onSerializing != null)
contract.OnSerializing = onSerializing;
if (onSerialized != null)
contract.OnSerialized = onSerialized;
if (onDeserializing != null)
contract.OnDeserializing = 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)
if (!t.IsGenericType || (t.GetGenericTypeDefinition() != typeof(ConcurrentDictionary<,>)))
contract.OnDeserialized = onDeserialized;
#else
contract.OnDeserialized = onDeserialized;
#endif
}
if (onError != null)
contract.OnError = onError;
}