-Fixed StringEnumConverter to throw a JsonSerializerException like the serializer throws for invalid enums

-Changed Windows Phone and Portable builds to use Microsoft.CSharp.dll directly
This commit is contained in:
James Newton-King
2013-03-23 12:48:41 +13:00
parent 271ce7f523
commit c4d375dd69
9 changed files with 137 additions and 30 deletions
@@ -24,6 +24,7 @@
#endregion
using System;
using System.IO;
using System.Runtime.Serialization;
using Newtonsoft.Json.Converters;
#if !NETFX_CORE
@@ -334,5 +335,30 @@ namespace Newtonsoft.Json.Tests.Converters
EnumClass c = JsonConvert.DeserializeObject<EnumClass>(json, new StringEnumConverter());
Assert.IsNull(c.NullableStoreColor2);
}
public void DeserializeInvalidString()
{
string json = "{ \"Value\" : \"Three\" }";
ExceptionAssert.Throws<JsonSerializationException>(
@"Error converting value ""Three"" to type 'Newtonsoft.Json.Tests.Converters.StringEnumConverterTests+MyEnum'. Path 'Value', line 1, position 19.",
() =>
{
var serializer = new JsonSerializer();
serializer.Converters.Add(new StringEnumConverter());
serializer.Deserialize<Bucket>(new JsonTextReader(new StringReader(json)));
});
}
public class Bucket
{
public MyEnum Value;
}
public enum MyEnum
{
Alpha,
Beta,
}
}
}
@@ -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.15917")]
[assembly: AssemblyFileVersion("5.0.1.15923")]
@@ -90,6 +90,40 @@ namespace Newtonsoft.Json.Tests.Serialization
[TestFixture]
public class JsonSerializerTest : TestFixtureBase
{
//[DataContract]
//public class BaseDataContract1
//{
// [DataMember(Name = "virtualMember")]
// public virtual string VirtualMember { get; set; }
// [DataMember(Name = "nonVirtualMember")]
// public string NonVirtualMember { get; set; }
// public virtual object NewMember { get; set; }
//}
//public class ChildDataContract1 : BaseDataContract1
//{
// [DataMember(Name = "NewMember")]
// public virtual new string NewMember { get; set; }
// public override string VirtualMember { get; set; }
// public string AddedMember { get; set; }
//}
//[Test]
//public void ChildDataContractTest1()
//{
// var cc = new ChildDataContract1
// {
// VirtualMember = "VirtualMember!",
// NonVirtualMember = "NonVirtualMember!",
// NewMember = "NewMember!"
// };
// string result = JsonConvert.SerializeObject(cc);
// Assert.AreEqual(@"{""NewMember"":""NewMember!"",""virtualMember"":""VirtualMember!"",""nonVirtualMember"":""NonVirtualMember!""}", result);
//}
[Test]
public void PersonTypedObjectDeserialization()
{
@@ -6450,6 +6484,21 @@ Parameter name: value",
}", json);
}
#if !(NET20 || NET35)
public class IgnoreDataMemberTestClass
{
[IgnoreDataMember]
public int Ignored { get; set; }
}
[Test]
public void IgnoreDataMemberTest()
{
string json = JsonConvert.SerializeObject(new IgnoreDataMemberTestClass() { Ignored = int.MaxValue }, Formatting.Indented);
Assert.AreEqual(@"{}", json);
}
#endif
#if !(NET20 || NET35)
[Test]
public void SerializeDataContractSerializationAttributes()
@@ -6462,6 +6511,12 @@ Parameter name: value",
IgnoreDataMemberAndDataMemberAttribute = "Value!"
};
//MemoryStream ms = new MemoryStream();
//DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(DataContractSerializationAttributesClass));
//serializer.WriteObject(ms, dataContract);
//Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
string json = JsonConvert.SerializeObject(dataContract, Formatting.Indented);
Assert.AreEqual(@"{
""DataMemberAttribute"": ""Value!"",
@@ -111,22 +111,30 @@ namespace Newtonsoft.Json.Converters
return null;
}
if (reader.TokenType == JsonToken.String)
try
{
string enumText = reader.Value.ToString();
if (enumText == string.Empty && isNullable)
return null;
if (reader.TokenType == JsonToken.String)
{
string enumText = reader.Value.ToString();
if (enumText == string.Empty && isNullable)
return null;
var map = GetEnumNameMap(t);
string resolvedEnumName;
map.TryGetBySecond(enumText, out resolvedEnumName);
resolvedEnumName = resolvedEnumName ?? enumText;
var map = GetEnumNameMap(t);
string resolvedEnumName;
map.TryGetBySecond(enumText, out resolvedEnumName);
resolvedEnumName = resolvedEnumName ?? enumText;
return Enum.Parse(t, resolvedEnumName, true);
return Enum.Parse(t, resolvedEnumName, true);
}
if (reader.TokenType == JsonToken.Integer)
return ConvertUtils.ConvertOrCast(reader.Value, CultureInfo.InvariantCulture, t);
}
catch (Exception ex)
{
throw JsonSerializationException.Create(reader, "Error converting value {0} to type '{1}'.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.FormatValueForPrint(reader.Value), objectType), ex);
}
if (reader.TokenType == JsonToken.Integer)
return ConvertUtils.ConvertOrCast(reader.Value, CultureInfo.InvariantCulture, t);
throw JsonSerializationException.Create(reader, "Unexpected token when parsing enum. Expected String or Integer, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
}
@@ -37,8 +37,6 @@
<Reference Include="System.Numerics" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
@@ -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.15917")]
[assembly: AssemblyFileVersion("5.0.1.15923")]
[assembly: CLSCompliant(true)]
@@ -671,24 +671,13 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
}
catch (Exception ex)
{
throw JsonSerializationException.Create(reader, "Error converting value {0} to type '{1}'.".FormatWith(CultureInfo.InvariantCulture, FormatValueForPrint(value), targetType), ex);
throw JsonSerializationException.Create(reader, "Error converting value {0} to type '{1}'.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.FormatValueForPrint(value), targetType), ex);
}
}
return value;
}
private string FormatValueForPrint(object value)
{
if (value == null)
return "{null}";
if (value is string)
return @"""" + value + @"""";
return value.ToString();
}
private void SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, object target)
{
object currentValue;
+23 -3
View File
@@ -29,7 +29,11 @@ using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
#if !(PORTABLE || WINDOWS_PHONE)
using System.Reflection;
#else
using Microsoft.CSharp.RuntimeBinder;
#endif
using System.Runtime.CompilerServices;
using System.Text;
using System.Globalization;
@@ -41,6 +45,7 @@ namespace Newtonsoft.Json.Utilities
{
internal static class BinderWrapper
{
#if !(PORTABLE || WINDOWS_PHONE)
#if !SILVERLIGHT
public const string CSharpAssemblyName = "Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
#else
@@ -95,9 +100,9 @@ namespace Newtonsoft.Json.Utilities
private static void CreateMemberCalls()
{
Type csharpArgumentInfoType = Type.GetType(CSharpArgumentInfoTypeName);
Type csharpBinderFlagsType = Type.GetType(CSharpBinderFlagsTypeName);
Type binderType = Type.GetType(BinderTypeName);
Type csharpArgumentInfoType = Type.GetType(CSharpArgumentInfoTypeName, true);
Type csharpBinderFlagsType = Type.GetType(CSharpBinderFlagsTypeName, true);
Type binderType = Type.GetType(BinderTypeName, true);
Type csharpArgumentInfoTypeEnumerableType = typeof (IEnumerable<>).MakeGenericType(csharpArgumentInfoType);
@@ -107,17 +112,32 @@ namespace Newtonsoft.Json.Utilities
MethodInfo setMemberMethod = binderType.GetMethod("SetMember", new[] {csharpBinderFlagsType, typeof (string), typeof (Type), csharpArgumentInfoTypeEnumerableType});
_setMemberCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(setMemberMethod);
}
#endif
public static CallSiteBinder GetMember(string name, Type context)
{
#if !(PORTABLE || WINDOWS_PHONE)
Init();
return (CallSiteBinder) _getMemberCall(null, 0, name, context, _getCSharpArgumentInfoArray);
#else
return Binder.GetMember(
CSharpBinderFlags.None, name, context, new[] {CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)});
#endif
}
public static CallSiteBinder SetMember(string name, Type context)
{
#if !(PORTABLE || WINDOWS_PHONE)
Init();
return (CallSiteBinder) _setMemberCall(null, 0, name, context, _setCSharpArgumentInfoArray);
#else
return Binder.SetMember(
CSharpBinderFlags.None, name, context, new[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant, null)
});
#endif
}
}
@@ -183,5 +183,16 @@ namespace Newtonsoft.Json.Utilities
localName = qualifiedName.Substring(colonPosition + 1);
}
}
internal static string FormatValueForPrint(object value)
{
if (value == null)
return "{null}";
if (value is string)
return @"""" + value + @"""";
return value.ToString();
}
}
}