-Refactor
This commit is contained in:
@@ -33,4 +33,4 @@ using System.Runtime.InteropServices;
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("6.0.0.0")]
|
||||
[assembly: AssemblyVersion("6.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("6.0.6.17911")]
|
||||
[assembly: AssemblyFileVersion("6.0.6.17924")]
|
||||
|
||||
@@ -445,6 +445,14 @@ namespace Newtonsoft.Json.Tests.Converters
|
||||
Assert.AreEqual(Bar.SerializeAsBaz, bars[2]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DuplicateNameEnumTest()
|
||||
{
|
||||
ExceptionAssert.Throws<JsonSerializationException>(
|
||||
() => JsonConvert.DeserializeObject<DuplicateNameEnum>("'foo_bar'", new StringEnumConverter()),
|
||||
@"Error converting value ""foo_bar"" to type 'Newtonsoft.Json.Tests.Converters.DuplicateNameEnum'. Path '', line 1, position 9.");
|
||||
}
|
||||
|
||||
// Define other methods and classes here
|
||||
[Flags]
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
@@ -468,6 +476,74 @@ namespace Newtonsoft.Json.Tests.Converters
|
||||
[EnumMember(Value = "baz")]
|
||||
SerializeAsBaz
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DataContractSerializerDuplicateNameEnumTest()
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
var s = new DataContractSerializer(typeof(DuplicateEnumNameTestClass));
|
||||
|
||||
ExceptionAssert.Throws<InvalidDataContractException>(() =>
|
||||
{
|
||||
s.WriteObject(ms, new DuplicateEnumNameTestClass
|
||||
{
|
||||
Value = DuplicateNameEnum.foo_bar,
|
||||
Value2 = DuplicateNameEnum2.foo_bar_NOT_USED
|
||||
});
|
||||
|
||||
Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
|
||||
|
||||
string xml = @"<DuplicateEnumNameTestClass xmlns=""http://schemas.datacontract.org/2004/07/Newtonsoft.Json.Tests.Converters"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">
|
||||
<Value>foo_bar</Value>
|
||||
<Value2>foo_bar</Value2>
|
||||
</DuplicateEnumNameTestClass>";
|
||||
|
||||
Console.WriteLine(xml);
|
||||
|
||||
var o = (DuplicateEnumNameTestClass)s.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(xml)));
|
||||
|
||||
Assert.AreEqual(DuplicateNameEnum.foo_bar, o.Value);
|
||||
Assert.AreEqual(DuplicateNameEnum2.FooBar, o.Value2);
|
||||
|
||||
}, "Type 'Newtonsoft.Json.Tests.Converters.DuplicateNameEnum' contains two members 'foo_bar' 'and 'FooBar' with the same name 'foo_bar'. Multiple members with the same name in one type are not supported. Consider changing one of the member names using EnumMemberAttribute attribute.");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !NET20
|
||||
[DataContract]
|
||||
public class DuplicateEnumNameTestClass
|
||||
{
|
||||
[DataMember]
|
||||
public DuplicateNameEnum Value { get; set; }
|
||||
[DataMember]
|
||||
public DuplicateNameEnum2 Value2 { get; set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public enum DuplicateNameEnum
|
||||
{
|
||||
[EnumMember]
|
||||
first = 0,
|
||||
[EnumMember]
|
||||
foo_bar = 1,
|
||||
[EnumMember(Value = "foo_bar")]
|
||||
FooBar = 2,
|
||||
[EnumMember]
|
||||
foo_bar_NOT_USED = 3
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public enum DuplicateNameEnum2
|
||||
{
|
||||
[EnumMember]
|
||||
first = 0,
|
||||
[EnumMember(Value = "foo_bar")]
|
||||
FooBar = 1,
|
||||
[EnumMember]
|
||||
foo_bar = 2,
|
||||
[EnumMember(Value = "TEST")]
|
||||
foo_bar_NOT_USED = 3
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -23,6 +23,7 @@
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
using System.Diagnostics;
|
||||
#if !(NET35 || NET20 || PORTABLE40)
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -52,6 +53,54 @@ namespace Newtonsoft.Json.Tests.Linq
|
||||
[TestFixture]
|
||||
public class DynamicTests : TestFixtureBase
|
||||
{
|
||||
private void UpdateValueCount(IDictionary<string, int> counts, dynamic d)
|
||||
{
|
||||
string s = d.ToString();
|
||||
|
||||
int c;
|
||||
if (!counts.TryGetValue(s, out c))
|
||||
{
|
||||
c = 0;
|
||||
}
|
||||
|
||||
c++;
|
||||
counts[s] = c;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeLargeDynamic()
|
||||
{
|
||||
dynamic d;
|
||||
|
||||
using (var jsonFile = System.IO.File.OpenText("large.json"))
|
||||
using (JsonTextReader jsonTextReader = new JsonTextReader(jsonFile))
|
||||
{
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
d = serializer.Deserialize(jsonTextReader);
|
||||
}
|
||||
|
||||
IDictionary<string, int> counts = new Dictionary<string, int>();
|
||||
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
foreach (dynamic o in d)
|
||||
{
|
||||
foreach (dynamic friend in o.friends)
|
||||
{
|
||||
UpdateValueCount(counts, friend.id);
|
||||
UpdateValueCount(counts, ((string) friend.name).Split(' ')[0]);
|
||||
}
|
||||
}
|
||||
|
||||
//foreach (KeyValuePair<string, int> keyValuePair in counts)
|
||||
//{
|
||||
// Console.WriteLine(keyValuePair.Key + ": " + keyValuePair.Value);
|
||||
//}
|
||||
|
||||
Console.WriteLine("Time (secs): " + sw.Elapsed.TotalSeconds);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void JObjectPropertyNames()
|
||||
{
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization;
|
||||
using Newtonsoft.Json.Tests.TestObjects;
|
||||
#if !(NET20 || NET35 || PORTABLE || ASPNETCORE50)
|
||||
using System.Numerics;
|
||||
@@ -792,6 +793,20 @@ namespace Newtonsoft.Json.Tests.Linq
|
||||
Assert.AreEqual(JTokenType.Integer, v.Type);
|
||||
StringComparison e6 = v.ToObject<StringComparison>();
|
||||
Assert.AreEqual(StringComparison.OrdinalIgnoreCase, e6);
|
||||
|
||||
// does not support EnumMember. breaking change to add
|
||||
ExceptionAssert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
d = new JValue("value_a");
|
||||
EnumA e7 = (EnumA)d;
|
||||
Assert.AreEqual(EnumA.ValueA, e7);
|
||||
}, "Requested value 'value_a' was not found.");
|
||||
}
|
||||
|
||||
public enum EnumA
|
||||
{
|
||||
[EnumMember(Value = "value_a")]
|
||||
ValueA
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -74,4 +74,4 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("6.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("6.0.6.17911")]
|
||||
[assembly: AssemblyFileVersion("6.0.6.17924")]
|
||||
|
||||
@@ -95,6 +95,24 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
[TestFixture]
|
||||
public class JsonSerializerTest : TestFixtureBase
|
||||
{
|
||||
#if !NET20
|
||||
public enum EnumA
|
||||
{
|
||||
[EnumMember(Value = "value_a")]
|
||||
ValueA
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeEnumsByName()
|
||||
{
|
||||
var e1 = JsonConvert.DeserializeObject<EnumA>("'ValueA'");
|
||||
Assert.AreEqual(EnumA.ValueA, e1);
|
||||
|
||||
var e2 = JsonConvert.DeserializeObject<EnumA>("'value_a'", new StringEnumConverter());
|
||||
Assert.AreEqual(EnumA.ValueA, e2);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !(NETFX_CORE || ASPNETCORE50 || NET20)
|
||||
[MetadataType(typeof(CustomerValidation))]
|
||||
public partial class CustomerWithMetadataType
|
||||
|
||||
@@ -33,7 +33,6 @@ using Newtonsoft.Json.Utilities;
|
||||
using Newtonsoft.Json.Utilities.LinqBridge;
|
||||
#else
|
||||
using System.Linq;
|
||||
|
||||
#endif
|
||||
|
||||
namespace Newtonsoft.Json.Converters
|
||||
@@ -43,8 +42,6 @@ namespace Newtonsoft.Json.Converters
|
||||
/// </summary>
|
||||
public class StringEnumConverter : JsonConverter
|
||||
{
|
||||
private static readonly ThreadSafeStore<Type, BidirectionalDictionary<string, string>> EnumMemberNamesPerType = new ThreadSafeStore<Type, BidirectionalDictionary<string, string>>(InitializeEnumType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the written enum text should be camel case.
|
||||
/// </summary>
|
||||
@@ -90,24 +87,9 @@ namespace Newtonsoft.Json.Converters
|
||||
}
|
||||
else
|
||||
{
|
||||
BidirectionalDictionary<string, string> map = EnumMemberNamesPerType.Get(e.GetType());
|
||||
Type enumType = e.GetType();
|
||||
|
||||
string[] names = enumName.Split(',');
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
{
|
||||
string name = names[i].Trim();
|
||||
|
||||
string resolvedEnumName;
|
||||
map.TryGetByFirst(name, out resolvedEnumName);
|
||||
resolvedEnumName = resolvedEnumName ?? name;
|
||||
|
||||
if (CamelCaseText)
|
||||
resolvedEnumName = StringUtils.ToCamelCase(resolvedEnumName);
|
||||
|
||||
names[i] = resolvedEnumName;
|
||||
}
|
||||
|
||||
string finalName = string.Join(", ", names);
|
||||
string finalName = EnumUtils.ToEnumName(enumType, enumName, CamelCaseText);
|
||||
|
||||
writer.WriteValue(finalName);
|
||||
}
|
||||
@@ -139,30 +121,7 @@ namespace Newtonsoft.Json.Converters
|
||||
if (reader.TokenType == JsonToken.String)
|
||||
{
|
||||
string enumText = reader.Value.ToString();
|
||||
if (enumText == string.Empty && isNullable)
|
||||
return null;
|
||||
|
||||
string finalEnumText;
|
||||
|
||||
BidirectionalDictionary<string, string> map = EnumMemberNamesPerType.Get(t);
|
||||
if (enumText.IndexOf(',') != -1)
|
||||
{
|
||||
string[] names = enumText.Split(',');
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
{
|
||||
string name = names[i].Trim();
|
||||
|
||||
names[i] = ResolvedEnumName(map, name);
|
||||
}
|
||||
|
||||
finalEnumText = string.Join(", ", names);
|
||||
}
|
||||
else
|
||||
{
|
||||
finalEnumText = ResolvedEnumName(map, enumText);
|
||||
}
|
||||
|
||||
return Enum.Parse(t, finalEnumText, true);
|
||||
return EnumUtils.ParseEnumName(enumText, isNullable, t);
|
||||
}
|
||||
|
||||
if (reader.TokenType == JsonToken.Integer)
|
||||
@@ -182,14 +141,6 @@ namespace Newtonsoft.Json.Converters
|
||||
throw JsonSerializationException.Create(reader, "Unexpected token {0} when parsing enum.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||
}
|
||||
|
||||
private static string ResolvedEnumName(BidirectionalDictionary<string, string> map, string enumText)
|
||||
{
|
||||
string resolvedEnumName;
|
||||
map.TryGetBySecond(enumText, out resolvedEnumName);
|
||||
resolvedEnumName = resolvedEnumName ?? enumText;
|
||||
return resolvedEnumName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can convert the specified object type.
|
||||
/// </summary>
|
||||
@@ -205,35 +156,5 @@ namespace Newtonsoft.Json.Converters
|
||||
|
||||
return t.IsEnum();
|
||||
}
|
||||
|
||||
private static BidirectionalDictionary<string, string> InitializeEnumType(Type type)
|
||||
{
|
||||
BidirectionalDictionary<string, string> map = new BidirectionalDictionary<string, string>(
|
||||
StringComparer.OrdinalIgnoreCase,
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (FieldInfo f in type.GetFields())
|
||||
{
|
||||
string n1 = f.Name;
|
||||
string n2;
|
||||
|
||||
#if !NET20
|
||||
n2 = f.GetCustomAttributes(typeof(EnumMemberAttribute), true)
|
||||
.Cast<EnumMemberAttribute>()
|
||||
.Select(a => a.Value)
|
||||
.SingleOrDefault() ?? f.Name;
|
||||
#else
|
||||
n2 = f.Name;
|
||||
#endif
|
||||
|
||||
string s;
|
||||
if (map.TryGetBySecond(n2, out s))
|
||||
throw new InvalidOperationException("Enum name '{0}' already exists on enum '{1}'.".FormatWith(CultureInfo.InvariantCulture, n2, type.Name));
|
||||
|
||||
map.Set(n1, n2);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,5 +91,5 @@ using System.Security;
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("6.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("6.0.6.17911")]
|
||||
[assembly: AssemblyFileVersion("6.0.6.17924")]
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Runtime.Serialization;
|
||||
#if NET20
|
||||
using Newtonsoft.Json.Utilities.LinqBridge;
|
||||
#else
|
||||
@@ -37,6 +38,38 @@ namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
internal static class EnumUtils
|
||||
{
|
||||
private static readonly ThreadSafeStore<Type, BidirectionalDictionary<string, string>> EnumMemberNamesPerType = new ThreadSafeStore<Type, BidirectionalDictionary<string, string>>(InitializeEnumType);
|
||||
|
||||
private static BidirectionalDictionary<string, string> InitializeEnumType(Type type)
|
||||
{
|
||||
BidirectionalDictionary<string, string> map = new BidirectionalDictionary<string, string>(
|
||||
StringComparer.OrdinalIgnoreCase,
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (FieldInfo f in type.GetFields())
|
||||
{
|
||||
string n1 = f.Name;
|
||||
string n2;
|
||||
|
||||
#if !NET20
|
||||
n2 = f.GetCustomAttributes(typeof(EnumMemberAttribute), true)
|
||||
.Cast<EnumMemberAttribute>()
|
||||
.Select(a => a.Value)
|
||||
.SingleOrDefault() ?? f.Name;
|
||||
#else
|
||||
n2 = f.Name;
|
||||
#endif
|
||||
|
||||
string s;
|
||||
if (map.TryGetBySecond(n2, out s))
|
||||
throw new InvalidOperationException("Enum name '{0}' already exists on enum '{1}'.".FormatWith(CultureInfo.InvariantCulture, n2, type.Name));
|
||||
|
||||
map.Set(n1, n2);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
public static IList<T> GetFlagsValues<T>(T value) where T : struct
|
||||
{
|
||||
Type enumType = typeof(T);
|
||||
@@ -112,9 +145,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
|
||||
List<object> values = new List<object>();
|
||||
|
||||
var fields = from field in enumType.GetFields()
|
||||
where field.IsLiteral
|
||||
select field;
|
||||
var fields = enumType.GetFields().Where(f => f.IsLiteral);
|
||||
|
||||
foreach (FieldInfo field in fields)
|
||||
{
|
||||
@@ -132,9 +163,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
|
||||
List<string> values = new List<string>();
|
||||
|
||||
var fields = from field in enumType.GetFields()
|
||||
where field.IsLiteral
|
||||
select field;
|
||||
var fields = enumType.GetFields().Where(f => f.IsLiteral);
|
||||
|
||||
foreach (FieldInfo field in fields)
|
||||
{
|
||||
@@ -143,5 +172,65 @@ namespace Newtonsoft.Json.Utilities
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
public static object ParseEnumName(string enumText, bool isNullable, Type t)
|
||||
{
|
||||
if (enumText == string.Empty && isNullable)
|
||||
return null;
|
||||
|
||||
string finalEnumText;
|
||||
|
||||
BidirectionalDictionary<string, string> map = EnumMemberNamesPerType.Get(t);
|
||||
if (enumText.IndexOf(',') != -1)
|
||||
{
|
||||
string[] names = enumText.Split(',');
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
{
|
||||
string name = names[i].Trim();
|
||||
|
||||
names[i] = ResolvedEnumName(map, name);
|
||||
}
|
||||
|
||||
finalEnumText = string.Join(", ", names);
|
||||
}
|
||||
else
|
||||
{
|
||||
finalEnumText = ResolvedEnumName(map, enumText);
|
||||
}
|
||||
|
||||
return Enum.Parse(t, finalEnumText, true);
|
||||
}
|
||||
|
||||
public static string ToEnumName(Type enumType, string enumText, bool camelCaseText)
|
||||
{
|
||||
BidirectionalDictionary<string, string> map = EnumMemberNamesPerType.Get(enumType);
|
||||
|
||||
string[] names = enumText.Split(',');
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
{
|
||||
string name = names[i].Trim();
|
||||
|
||||
string resolvedEnumName;
|
||||
map.TryGetByFirst(name, out resolvedEnumName);
|
||||
resolvedEnumName = resolvedEnumName ?? name;
|
||||
|
||||
if (camelCaseText)
|
||||
resolvedEnumName = StringUtils.ToCamelCase(resolvedEnumName);
|
||||
|
||||
names[i] = resolvedEnumName;
|
||||
}
|
||||
|
||||
string finalName = string.Join(", ", names);
|
||||
|
||||
return finalName;
|
||||
}
|
||||
|
||||
private static string ResolvedEnumName(BidirectionalDictionary<string, string> map, string enumText)
|
||||
{
|
||||
string resolvedEnumName;
|
||||
map.TryGetBySecond(enumText, out resolvedEnumName);
|
||||
resolvedEnumName = resolvedEnumName ?? enumText;
|
||||
return resolvedEnumName;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user