From bf5b50f88b8b638dcebedc19294475f62806b3d6 Mon Sep 17 00:00:00 2001 From: Jason Mead Date: Mon, 1 Dec 2014 00:27:47 -0600 Subject: [PATCH 1/2] Serialize and deserialize Enum values as strings --- .../EnumDeserializeTests.cs | 102 ++++++++++++++++++ .../EnumSerializeTests.cs | 100 +++++++++++++++++ ...SerializeObject.KnownNonPrimitive.Tests.cs | 2 +- src/SimpleJson.Tests/SimpleJson.Tests.csproj | 2 + src/SimpleJson/SimpleJson.cs | 41 +++---- 5 files changed, 227 insertions(+), 20 deletions(-) create mode 100644 src/SimpleJson.Tests/PocoDeserializerTests/EnumDeserializeTests.cs create mode 100644 src/SimpleJson.Tests/PocoJsonSerializerTests/EnumSerializeTests.cs diff --git a/src/SimpleJson.Tests/PocoDeserializerTests/EnumDeserializeTests.cs b/src/SimpleJson.Tests/PocoDeserializerTests/EnumDeserializeTests.cs new file mode 100644 index 0000000..e76367f --- /dev/null +++ b/src/SimpleJson.Tests/PocoDeserializerTests/EnumDeserializeTests.cs @@ -0,0 +1,102 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) 2011, The Outercurve Foundation. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.opensource.org/licenses/mit-license.php +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Nathan Totten (ntotten.com), Jim Zimmerman (jimzimmerman.com) and Prabir Shrestha (prabir.me) +// https://github.com/facebook-csharp-sdk/simple-json +//----------------------------------------------------------------------- + +namespace SimpleJson.Tests.PocoDeserializerTests +{ + using System; + +#if NUNIT + using TestClass = NUnit.Framework.TestFixtureAttribute; + using TestMethod = NUnit.Framework.TestAttribute; + using TestCleanup = NUnit.Framework.TearDownAttribute; + using TestInitialize = NUnit.Framework.SetUpAttribute; + using ClassCleanup = NUnit.Framework.TestFixtureTearDownAttribute; + using ClassInitialize = NUnit.Framework.TestFixtureSetUpAttribute; + using NUnit.Framework; +#else +#if NETFX_CORE + using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; +#else + using Microsoft.VisualStudio.TestTools.UnitTesting; +#endif +#endif + + [TestClass] + public class EnumDeserializeTests + { + [TestMethod] + public void DeserializeEnumStringValue() + { + var json = "{\"Value\":\"Two\"}"; + + var result = SimpleJson.DeserializeObject(json); + Assert.AreEqual(Values.Two, result.Value); + } + + public class X + { + public Values Value { get; set; } + } + } + + + [TestClass] + public class NullableEnumDeserializeTests + { + [TestMethod] + public void DeserializeNullEnumValue() + { + var json = "{}"; + + var result = SimpleJson.DeserializeObject(json); + + Assert.IsNull(result.Value); + } + + [TestMethod] + public void DeserializeNullValue() + { + var json = "{\"Value\":null}"; + + var result = SimpleJson.DeserializeObject(json); + Assert.IsNull(result.Value); + } + + [TestMethod] + public void DeserializeNullableEnumWithValue() + { + var json = "{\"Value\":\"Two\"}"; + var result = SimpleJson.DeserializeObject(json); + Assert.AreEqual(Values.Two, result.Value); + } + + public class X + { + public Values? Value { get; set; } + } + } + + public enum Values + { + One, + Two, + Three + } + +} diff --git a/src/SimpleJson.Tests/PocoJsonSerializerTests/EnumSerializeTests.cs b/src/SimpleJson.Tests/PocoJsonSerializerTests/EnumSerializeTests.cs new file mode 100644 index 0000000..bcd2fac --- /dev/null +++ b/src/SimpleJson.Tests/PocoJsonSerializerTests/EnumSerializeTests.cs @@ -0,0 +1,100 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) 2011, The Outercurve Foundation. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.opensource.org/licenses/mit-license.php +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Nathan Totten (ntotten.com), Jim Zimmerman (jimzimmerman.com) and Prabir Shrestha (prabir.me) +// https://github.com/facebook-csharp-sdk/simple-json +//----------------------------------------------------------------------- + +namespace SimpleJson.Tests.PocoJsonSerializerTests +{ + using System; + +#if NUNIT + using TestClass = NUnit.Framework.TestFixtureAttribute; + using TestMethod = NUnit.Framework.TestAttribute; + using TestCleanup = NUnit.Framework.TearDownAttribute; + using TestInitialize = NUnit.Framework.SetUpAttribute; + using ClassCleanup = NUnit.Framework.TestFixtureTearDownAttribute; + using ClassInitialize = NUnit.Framework.TestFixtureSetUpAttribute; + using NUnit.Framework; +#else +#if NETFX_CORE + using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; +#else + using Microsoft.VisualStudio.TestTools.UnitTesting; +#endif +#endif + + [TestClass] + public class EnumSerializeTests + { + [TestMethod] + public void SerializeEnumAsStringValue() + { + var obj = new SerializeEnumClass() + { + Value = Values.Two + }; + + var json = SimpleJson.SerializeObject(obj); + + Assert.AreEqual("{\"Value\":\"Two\"}", json); + } + + public class SerializeEnumClass + { + public Values Value { get; set; } + } + } + + [TestClass] + public class NullableEnumSerializeTest + { + [TestMethod] + public void SerializeNullableEnumWithNoValue() + { + var obj = new SerializeNullableEnumClass(); + + var json = SimpleJson.SerializeObject(obj); + + Assert.AreEqual("{\"Value\":null}", json); + } + + [TestMethod] + public void SerializeNullableEnumWithValue() + { + var obj = new SerializeNullableEnumClass + { + Value = Values.Two + }; + + var json = SimpleJson.SerializeObject(obj); + + Assert.AreEqual("{\"Value\":\"Two\"}", json); + } + + public class SerializeNullableEnumClass + { + public Values? Value { get; set; } + } + } + + public enum Values + { + One, + Two, + Three + } +} diff --git a/src/SimpleJson.Tests/SerializeObject.KnownNonPrimitive.Tests.cs b/src/SimpleJson.Tests/SerializeObject.KnownNonPrimitive.Tests.cs index 2620e8c..5078b06 100644 --- a/src/SimpleJson.Tests/SerializeObject.KnownNonPrimitive.Tests.cs +++ b/src/SimpleJson.Tests/SerializeObject.KnownNonPrimitive.Tests.cs @@ -54,7 +54,7 @@ public void GuidSerialization() public void EnumSerialization() { string json = SimpleJson.SerializeObject(StringComparison.CurrentCultureIgnoreCase); - Assert.AreEqual("1", json); + Assert.AreEqual("\"CurrentCultureIgnoreCase\"", json); } [TestMethod] diff --git a/src/SimpleJson.Tests/SimpleJson.Tests.csproj b/src/SimpleJson.Tests/SimpleJson.Tests.csproj index eafe9c8..960c75d 100644 --- a/src/SimpleJson.Tests/SimpleJson.Tests.csproj +++ b/src/SimpleJson.Tests/SimpleJson.Tests.csproj @@ -71,11 +71,13 @@ + + diff --git a/src/SimpleJson/SimpleJson.cs b/src/SimpleJson/SimpleJson.cs index 2ab9742..13485cb 100644 --- a/src/SimpleJson/SimpleJson.cs +++ b/src/SimpleJson/SimpleJson.cs @@ -522,7 +522,7 @@ static class SimpleJson static SimpleJson() { EscapeTable = new char[93]; - EscapeTable['"'] = '"'; + EscapeTable['"'] = '"'; EscapeTable['\\'] = '\\'; EscapeTable['\b'] = 'b'; EscapeTable['\f'] = 'f'; @@ -556,7 +556,7 @@ public static object DeserializeObject(string json) /// /// Returns true if successfull otherwise false. /// - [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification="Need to support .NET 2")] + [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification = "Need to support .NET 2")] public static bool TryDeserializeObject(string json, out object obj) { bool success = true; @@ -1222,7 +1222,7 @@ public static DataContractJsonSerializerStrategy DataContractJsonSerializerStrat #endif } - + [GeneratedCode("simple-json", "1.0.0")] #if SIMPLE_JSON_INTERNAL internal @@ -1231,7 +1231,7 @@ public static DataContractJsonSerializerStrategy DataContractJsonSerializerStrat #endif interface IJsonSerializerStrategy { - [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification="Need to support .NET 2")] + [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification = "Need to support .NET 2")] bool TrySerializeNonPrimitiveObject(object input, out object output); object DeserializeObject(object value, Type type); } @@ -1330,12 +1330,12 @@ public virtual object DeserializeObject(object value, Type type) if (type == null) throw new ArgumentNullException("type"); string str = value as string; - if (type == typeof (Guid) && string.IsNullOrEmpty(str)) + if (type == typeof(Guid) && string.IsNullOrEmpty(str)) return default(Guid); if (value == null) return null; - + object obj = null; if (str != null) @@ -1350,19 +1350,22 @@ public virtual object DeserializeObject(object value, Type type) return new Guid(str); if (type == typeof(Uri)) { - bool isValid = Uri.IsWellFormedUriString(str, UriKind.RelativeOrAbsolute); + bool isValid = Uri.IsWellFormedUriString(str, UriKind.RelativeOrAbsolute); Uri result; if (isValid && Uri.TryCreate(str, UriKind.RelativeOrAbsolute, out result)) return result; - return null; + return null; } - - if (type == typeof(string)) - return str; + if (type.IsEnum || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type).IsEnum)) + { + return Enum.Parse(ReflectionUtils.IsNullableType(type) ? Nullable.GetUnderlyingType(type) : type, str, true); + } + if (type == typeof(string)) + return str; - return Convert.ChangeType(str, type, CultureInfo.InvariantCulture); + return Convert.ChangeType(str, type, CultureInfo.InvariantCulture); } else { @@ -1379,7 +1382,7 @@ public virtual object DeserializeObject(object value, Type type) } else if (value is bool) return value; - + bool valueIsLong = value is long; bool valueIsDouble = value is double; if ((valueIsLong && type == typeof(long)) || (valueIsDouble && type == typeof(double))) @@ -1466,10 +1469,10 @@ public virtual object DeserializeObject(object value, Type type) protected virtual object SerializeEnum(Enum p) { - return Convert.ToDouble(p, CultureInfo.InvariantCulture); + return p.ToString(); } - [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification="Need to support .NET 2")] + [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification = "Need to support .NET 2")] protected virtual bool TrySerializeKnownTypes(object input, out object output) { bool returnValue = true; @@ -1494,7 +1497,7 @@ protected virtual bool TrySerializeKnownTypes(object input, out object output) } return returnValue; } - [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification="Need to support .NET 2")] + [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification = "Need to support .NET 2")] protected virtual bool TrySerializeUnknownTypes(object input, out object output) { if (input == null) throw new ArgumentNullException("input"); @@ -1596,7 +1599,7 @@ private static bool CanAdd(MemberInfo info, out string jsonKey) namespace Reflection { // This class is meant to be copied into other libraries. So we want to exclude it from Code Analysis rules - // that might be in place in the target project. + // that might be in place in the target project. [GeneratedCode("reflection-utils", "1.0.0")] #if SIMPLE_JSON_REFLECTION_UTILS_PUBLIC public @@ -1649,7 +1652,7 @@ public static Type GetGenericListElementType(Type type) foreach (Type implementedInterface in interfaces) { if (IsTypeGeneric(implementedInterface) && - implementedInterface.GetGenericTypeDefinition() == typeof (IList<>)) + implementedInterface.GetGenericTypeDefinition() == typeof(IList<>)) { return GetGenericTypeArguments(implementedInterface)[0]; } @@ -1699,7 +1702,7 @@ public static bool IsTypeGenericeCollectionInterface(Type type) || genericDefinition == typeof(IReadOnlyCollection<>) || genericDefinition == typeof(IReadOnlyList<>) #endif - ); +); } public static bool IsAssignableFrom(Type type1, Type type2) From 4bb84f84643b440eb1a9f51425568313c68ee808 Mon Sep 17 00:00:00 2001 From: Jonathan Channon Date: Thu, 28 Jul 2016 14:46:15 +0100 Subject: [PATCH 2/2] added fix to this PR as described by @amccorma --- src/SimpleJson/SimpleJson.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/SimpleJson/SimpleJson.cs b/src/SimpleJson/SimpleJson.cs index 13485cb..ac3fdc9 100644 --- a/src/SimpleJson/SimpleJson.cs +++ b/src/SimpleJson/SimpleJson.cs @@ -1358,10 +1358,7 @@ public virtual object DeserializeObject(object value, Type type) return null; } - if (type.IsEnum || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type).IsEnum)) - { - return Enum.Parse(ReflectionUtils.IsNullableType(type) ? Nullable.GetUnderlyingType(type) : type, str, true); - } + if (type == typeof(string)) return str; @@ -1385,6 +1382,17 @@ public virtual object DeserializeObject(object value, Type type) bool valueIsLong = value is long; bool valueIsDouble = value is double; + if (type.IsEnum) + { + if (value is double || value is int || value is long) + { + return Enum.ToObject(type, Convert.ToInt32(value.ToString())); + } + else if (value is string) + { + return Enum.Parse(type, value.ToString()); + } + } if ((valueIsLong && type == typeof(long)) || (valueIsDouble && type == typeof(double))) return value; if ((valueIsDouble && type != typeof(double)) || (valueIsLong && type != typeof(long)))