-Added additional ToString overloads to JValue

-Fixed poor error message when dynamic type cannot be created during deserialization
-Fixed error when setting a null value on a dynamic type during deserialization
-Fixed JsonTextReader.ReadAsDecimal not attempting to convert string values to decimal
This commit is contained in:
JamesNK
2011-02-24 10:14:08 +00:00
parent 1824aa4b59
commit 71446e9772
8 changed files with 169 additions and 11 deletions
@@ -185,7 +185,7 @@ namespace Newtonsoft.Json.Tests.Linq
Assert.AreEqual("", d.Null.ToString());
Assert.AreEqual("1", d.Integer.ToString());
Assert.AreEqual("1.1", d.Float.ToString());
Assert.AreEqual("1.1", d.Float.ToString(CultureInfo.InvariantCulture));
Assert.AreEqual("12/29/2000 23:51:10", d.DateTime.ToString(null, CultureInfo.InvariantCulture));
Assert.AreEqual("True", d.Boolean.ToString());
Assert.AreEqual("A string lol!", d.String.ToString());
@@ -25,6 +25,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using NUnit.Framework;
@@ -285,7 +286,7 @@ keyword such as type of business.""
1264118400000
)", o.Property("Establised").Value.ToString());
Assert.AreEqual(@"""Width"": 1.1", o.Property("Width").ToString());
Assert.AreEqual(@"1.1", o.Property("Width").Value.ToString());
Assert.AreEqual(@"1.1", ((JValue)o.Property("Width").Value).ToString(CultureInfo.InvariantCulture));
Assert.AreEqual(@"""Open"": false", o.Property("Open").ToString());
Assert.AreEqual(@"False", o.Property("Open").Value.ToString());
@@ -182,6 +182,103 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.AreEqual("Child text!", n.DynamicChildObject.Text);
Assert.AreEqual(int.MinValue, n.DynamicChildObject.Integer);
}
[Test]
[ExpectedException(typeof(JsonSerializationException), ExpectedMessage = "Unable to find a default constructor to use for type System.Dynamic.DynamicObject.")]
public void NoPublicDefaultConstructor()
{
var settings = new JsonSerializerSettings();
settings.NullValueHandling = NullValueHandling.Ignore;
var json = @"{
""contributors"": null
}";
JsonConvert.DeserializeObject<DynamicObject>(json, settings);
}
public class DictionaryDynamicObject : DynamicObject
{
public IDictionary<string, object> Values { get; private set; }
protected DictionaryDynamicObject()
{
Values = new Dictionary<string, object>();
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
Values[binder.Name] = value;
return true;
}
}
[Test]
public void AllowNonPublicDefaultConstructor()
{
var settings = new JsonSerializerSettings();
settings.ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor;
var json = @"{
""contributors"": null,
""retweeted"": false,
""text"": ""Guys SX4 diesel is launched.what are your plans?catch us at #facebook http://bit.ly/dV3H1a #auto #car #maruti #india #delhi"",
""in_reply_to_user_id_str"": null,
""retweet_count"": 0,
""geo"": null,
""id_str"": ""40678260320768000"",
""in_reply_to_status_id"": null,
""source"": ""<a href=\""http://www.tweetdeck.com\"" rel=\""nofollow\"">TweetDeck</a>"",
""created_at"": ""Thu Feb 24 07:43:47 +0000 2011"",
""place"": null,
""coordinates"": null,
""truncated"": false,
""favorited"": false,
""user"": {
""profile_background_image_url"": ""http://a1.twimg.com/profile_background_images/206944715/twitter_bg.jpg"",
""url"": ""http://bit.ly/dcFwWC"",
""screen_name"": ""marutisuzukisx4"",
""verified"": false,
""friends_count"": 45,
""description"": ""This is the Official Maruti Suzuki SX4 Twitter ID! Men are Back - mail us on social (at) sx4bymaruti (dot) com"",
""follow_request_sent"": null,
""time_zone"": ""Chennai"",
""profile_text_color"": ""333333"",
""location"": ""India"",
""notifications"": null,
""profile_sidebar_fill_color"": ""efefef"",
""id_str"": ""196143889"",
""contributors_enabled"": false,
""lang"": ""en"",
""profile_background_tile"": false,
""created_at"": ""Tue Sep 28 12:55:15 +0000 2010"",
""followers_count"": 117,
""show_all_inline_media"": true,
""listed_count"": 1,
""geo_enabled"": true,
""profile_link_color"": ""009999"",
""profile_sidebar_border_color"": ""eeeeee"",
""protected"": false,
""name"": ""Maruti Suzuki SX4"",
""statuses_count"": 637,
""following"": null,
""profile_use_background_image"": true,
""profile_image_url"": ""http://a3.twimg.com/profile_images/1170694644/Slide1_normal.JPG"",
""id"": 196143889,
""is_translator"": false,
""utc_offset"": 19800,
""favourites_count"": 0,
""profile_background_color"": ""131516""
},
""in_reply_to_screen_name"": null,
""id"": 40678260320768000,
""in_reply_to_status_id_str"": null,
""in_reply_to_user_id"": null
}";
DictionaryDynamicObject foo = JsonConvert.DeserializeObject<DictionaryDynamicObject>(json, settings);
Assert.AreEqual(false, foo.Values["retweeted"]);
}
}
}
#endif
@@ -28,6 +28,7 @@ using System.Collections.Generic;
#if !SILVERLIGHT && !PocketPC && !NET20
using System.ComponentModel.DataAnnotations;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Web.Script.Serialization;
#endif
using System.Text;
@@ -4178,5 +4179,29 @@ keyword such as type of business.""
""Name"": null
}", json);
}
public class DeserializeStringConvert
{
public string Name { get; set; }
public int Age { get; set; }
public double Height { get; set; }
public decimal Price { get; set; }
}
[Test]
public void DeserializeStringEnglish()
{
string json = @"{
'Name': 'James Hughes',
'Age': '40',
'Height': '44.4',
'Price': '4'
}";
DeserializeStringConvert p = JsonConvert.DeserializeObject<DeserializeStringConvert>(json);
Assert.AreEqual(40, p.Age);
Assert.AreEqual(44.4, p.Height);
Assert.AreEqual(4d, p.Price);
}
}
}
+7
View File
@@ -348,6 +348,13 @@ namespace Newtonsoft.Json
if (TokenType == JsonToken.Float)
return (decimal?)Value;
decimal d;
if (TokenType == JsonToken.String && decimal.TryParse((string)Value, NumberStyles.Number, CultureInfo.InvariantCulture, out d))
{
SetToken(JsonToken.Float, d);
return d;
}
throw CreateJsonReaderException("Unexpected token when reading decimal: {0}. Line {1}, position {2}.", TokenType, _currentLineNumber, _currentLinePosition);
}
+24
View File
@@ -458,6 +458,30 @@ namespace Newtonsoft.Json.Linq
return _value.ToString();
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <param name="format">The format.</param>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public string ToString(string format)
{
return ToString(format, CultureInfo.CurrentCulture);
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <param name="formatProvider">The format provider.</param>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public string ToString(IFormatProvider formatProvider)
{
return ToString(null, formatProvider);
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
@@ -228,7 +228,7 @@ namespace Newtonsoft.Json.Serialization
case JsonToken.Boolean:
case JsonToken.Date:
case JsonToken.Bytes:
return EnsureType(reader.Value, objectType);
return EnsureType(reader.Value, CultureInfo.InvariantCulture, objectType);
case JsonToken.String:
// convert empty string to null automatically for nullable types
if (string.IsNullOrEmpty((string)reader.Value) &&
@@ -240,7 +240,7 @@ namespace Newtonsoft.Json.Serialization
if (objectType == typeof(byte[]))
return Convert.FromBase64String((string)reader.Value);
return EnsureType(reader.Value, objectType);
return EnsureType(reader.Value, CultureInfo.InvariantCulture, objectType);
case JsonToken.StartConstructor:
case JsonToken.EndConstructor:
string constructorName = reader.Value.ToString();
@@ -251,7 +251,7 @@ namespace Newtonsoft.Json.Serialization
if (objectType == typeof (DBNull))
return DBNull.Value;
return EnsureType(reader.Value, objectType);
return EnsureType(reader.Value, CultureInfo.InvariantCulture, objectType);
case JsonToken.Raw:
return new JRaw((string)reader.Value);
case JsonToken.Comment:
@@ -463,7 +463,7 @@ namespace Newtonsoft.Json.Serialization
);
}
private object EnsureType(object value, Type targetType)
private object EnsureType(object value, CultureInfo culture, Type targetType)
{
if (targetType == null)
return value;
@@ -476,7 +476,7 @@ namespace Newtonsoft.Json.Serialization
{
try
{
return ConvertUtils.ConvertOrCast(value, CultureInfo.InvariantCulture, targetType);
return ConvertUtils.ConvertOrCast(value, culture, targetType);
}
catch (Exception ex)
{
@@ -612,7 +612,7 @@ namespace Newtonsoft.Json.Serialization
object keyValue;
try
{
keyValue = EnsureType(reader.Value, contract.DictionaryKeyType);
keyValue = EnsureType(reader.Value, CultureInfo.InvariantCulture, contract.DictionaryKeyType);
}
catch (Exception ex)
{
@@ -776,9 +776,9 @@ namespace Newtonsoft.Json.Serialization
if (contract.DefaultCreator != null &&
(!contract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor))
{
newObject = (IDynamicMetaObjectProvider)contract.DefaultCreator();
}
else
throw new JsonSerializationException("Unable to find a default constructor to use for type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
if (id != null)
Serializer.ReferenceResolver.AddReference(id, newObject);
@@ -98,6 +98,8 @@ namespace Newtonsoft.Json.Utilities
public static bool TryGetMember(this IDynamicMetaObjectProvider dynamicProvider, string name, out object value)
{
ValidationUtils.ArgumentNotNull(dynamicProvider, "dynamicProvider");
GetMemberBinder getMemberBinder = (GetMemberBinder) BinderWrapper.GetMember(name, typeof (DynamicUtils));
CallSite<Func<CallSite, object, object>> callSite = CallSite<Func<CallSite, object, object>>.Create(new NoThrowGetBinderMember(getMemberBinder));
@@ -118,7 +120,9 @@ namespace Newtonsoft.Json.Utilities
public static bool TrySetMember(this IDynamicMetaObjectProvider dynamicProvider, string name, object value)
{
SetMemberBinder binder = (SetMemberBinder) BinderWrapper.SetMember(name, value.GetType());
ValidationUtils.ArgumentNotNull(dynamicProvider, "dynamicProvider");
SetMemberBinder binder = (SetMemberBinder)BinderWrapper.SetMember(name, typeof(DynamicUtils));
var setterSite = CallSite<Func<CallSite, object, object, object>>.Create(new NoThrowSetBinderMember(binder));