diff --git a/Kivikko.Json.Tests/JsonUtilsTests.cs b/Kivikko.Json.Tests/JsonUtilsTests.cs index be627d5..a9c1aac 100644 --- a/Kivikko.Json.Tests/JsonUtilsTests.cs +++ b/Kivikko.Json.Tests/JsonUtilsTests.cs @@ -115,6 +115,7 @@ public static IEnumerable FromJsonCases() yield return new TestCaseData(typeof(IEnumerable), "[1,2]").Returns(new[] { 1, 2 }); yield return new TestCaseData(typeof(List), "[1,2]").Returns(new List { 1, 2 }); yield return new TestCaseData(typeof(List>), "[[1,2],[3,4]]").Returns(new List> { new() { 1, 2 }, new() { 3, 4} }); + yield return new TestCaseData(typeof(HashSet), "[1,2]").Returns(new HashSet { 1, 2 }); yield return new TestCaseData(typeof(int[][]), "[[1,2],[3,4]]").Returns(new[] { new[] { 1, 2 }, new[] { 3, 4 } }); yield return new TestCaseData(typeof((string, int)), "{\"Item1\":\"A\",\"Item2\":1}").Returns(("A", 1)); yield return new TestCaseData(typeof(Dictionary), "{\"1\":2,\"2\":3}").Returns(new Dictionary { [1] = 2, [2] = 3 }); @@ -124,7 +125,7 @@ public static IEnumerable FromJsonCases() yield return new TestCaseData(typeof(Dictionary>), "{\"1\":{\"2\":3,\"3\":4},\"2\":{\"3\":4}}").Returns(new Dictionary> { [1] = new() { [2] = 3, [3] = 4 }, [2] = new() { [3] = 4 } }); yield return new TestCaseData(typeof(NestedClass), "{Enum:1,Integer:5}").Returns(new NestedClass { Enum = TestEnum.Value3, Integer = 5}); yield return new TestCaseData(typeof(NestedClass), "{\"Enum\":1,\"Integer\":5}").Returns(new NestedClass { Enum = TestEnum.Value3, Integer = 5}); - yield return new TestCaseData(typeof(TestClass), "{\"NestedClass\":{\"Bool\":true,\"Double\":3.141592653589793,\"Integer\":5,\"DateTime\":\"2024-01-11T14:15:16+05:00\",\"Time\":\"1.02:03:04.0050060\",\"StringArray\":[\"A\",\"B\",\"C\"],\"StringEnumerable\":[\"K\",\"L\",\"M\"],\"StringList\":[\"X\",\"Y\",\"Z\"],\"Dictionary\":{\"1\":\"One\",\"2\":\"Two\",\"3\":\"Three\"}},\"Classes\":[{},{\"Enum\":-1},{\"Integer\":0},{\"Integer\":1,\"Enum\":1}],\"ClassesDictionary\":{\"0\":{\"Integer\":0},\"1\":{\"Integer\":1},\"2\":{\"Integer\":2}},\"String\":\"Hello\"}").Returns( + yield return new TestCaseData(typeof(TestClass), "{\"NestedClass\":{\"Bool\":true,\"Double\":3.141592653589793,\"Integer\":5,\"DateTime\":\"2024-01-11T14:15:16+05:00\",\"Time\":\"1.02:03:04.0050060\",\"HashSet\":[1,2,3],\"StringArray\":[\"A\",\"B\",\"C\"],\"StringEnumerable\":[\"K\",\"L\",\"M\"],\"StringList\":[\"X\",\"Y\",\"Z\"],\"Dictionary\":{\"1\":\"One\",\"2\":\"Two\",\"3\":\"Three\"}},\"Classes\":[{},{\"Enum\":-1},{\"Integer\":0},{\"Integer\":1,\"Enum\":1}],\"ClassesDictionary\":{\"0\":{\"Integer\":0},\"1\":{\"Integer\":1},\"2\":{\"Integer\":2}},\"String\":\"Hello\"}").Returns( new TestClass { String = "Hello", @@ -135,6 +136,7 @@ public static IEnumerable FromJsonCases() Integer = 5, DateTime = new DateTime(2024, 01, 11, 14, 15, 16, DateTimeKind.Local), Time = new TimeSpan(days: 1, hours: 2, minutes: 3, seconds: 4, milliseconds: 5, microseconds: 6), + HashSet = new HashSet { 1, 2, 3 }, StringArray = new[] { "A", "B", "C" }, StringEnumerable = new[] { "K", "L", "M" }, StringList = new List { "X", "Y", "Z" }, diff --git a/Kivikko.Json.Tests/Models/Model1/NestedClass.cs b/Kivikko.Json.Tests/Models/Model1/NestedClass.cs index 080058e..c090900 100644 --- a/Kivikko.Json.Tests/Models/Model1/NestedClass.cs +++ b/Kivikko.Json.Tests/Models/Model1/NestedClass.cs @@ -8,6 +8,7 @@ public class NestedClass public TestEnum Enum { get; set; } public DateTime? DateTime { get; set; } public TimeSpan? Time { get; set; } + public HashSet? HashSet { get; set; } public string[]? StringArray { get; set; } public IEnumerable? StringEnumerable { get; set; } public List? StringList { get; set; } diff --git a/Kivikko.Json/JsonUtils.cs b/Kivikko.Json/JsonUtils.cs index 1614a88..33eeca5 100644 --- a/Kivikko.Json/JsonUtils.cs +++ b/Kivikko.Json/JsonUtils.cs @@ -200,28 +200,44 @@ private object GetObjectFromJson(string json, Type type) setValue(typedArray); } - else if ( - propertyType.IsGenericType && - propertyType.GetInterfaces().Any(i => i == typeof(IDictionary)) && - value is IDictionary valueDictionary) + else if (propertyType.IsGenericType) { - var genericArgs = propertyType.GetGenericArguments(); - var keyType = genericArgs[0]; - var valueType = genericArgs[1]; - var typedDictionary = (IDictionary)Activator.CreateInstance(typeof(Dictionary<,>).MakeGenericType(keyType, valueType)); - foreach (DictionaryEntry entry in valueDictionary) typedDictionary.Add(entry.Key, entry.Value); - setValue(typedDictionary); - } + var interfaces = propertyType.GetInterfaces(); + + if (interfaces.Any(i => i == typeof(IDictionary)) && + value is IDictionary valueDictionary) + { + var genericArgs = propertyType.GetGenericArguments(); + var keyType = genericArgs[0]; + var valueType = genericArgs[1]; + var typedDictionary = (IDictionary)Activator.CreateInstance(typeof(Dictionary<,>).MakeGenericType(keyType, valueType)); + foreach (DictionaryEntry entry in valueDictionary) typedDictionary.Add(entry.Key, entry.Value); + setValue(typedDictionary); + } - else if ( - propertyType.IsGenericType && - propertyType.GetInterfaces().Any(i => i == typeof(IEnumerable)) && - propertyType.GetGenericArguments()[0] is { } listElementType && - value is ICollection valueCollection) - { - var typedList = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(listElementType)); - foreach (var v in valueCollection) typedList.Add(v); - setValue(typedList); + else if ( + interfaces.Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ISet<>)) && + propertyType.GetGenericArguments()[0] is { } setElementType && + value is ICollection setValueCollection) + { + var typedSet = Activator.CreateInstance(typeof(HashSet<>).MakeGenericType(setElementType), setValueCollection); + setValue(typedSet); + } + + else if ( + interfaces.Any(i => i == typeof(IEnumerable)) && + propertyType.GetGenericArguments()[0] is { } listElementType && + value is ICollection valueCollection) + { + var typedList = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(listElementType)); + foreach (var v in valueCollection) typedList.Add(v); + setValue(typedList); + } + + else + { + setValue(value); + } } else diff --git a/Kivikko.Json/Kivikko.Json.nuspec b/Kivikko.Json/Kivikko.Json.nuspec index 859c6e7..1ac768d 100644 --- a/Kivikko.Json/Kivikko.Json.nuspec +++ b/Kivikko.Json/Kivikko.Json.nuspec @@ -2,7 +2,7 @@ Kivikko.Json - 1.0.8 + 1.0.9 Kivikko.Json Sergei Petrov false diff --git a/Kivikko.Json/Properties/AssemblyInfo.cs b/Kivikko.Json/Properties/AssemblyInfo.cs index b428f54..6273214 100644 --- a/Kivikko.Json/Properties/AssemblyInfo.cs +++ b/Kivikko.Json/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.8.0")] -[assembly: AssemblyFileVersion("1.0.8.0")] \ No newline at end of file +[assembly: AssemblyVersion("1.0.9.0")] +[assembly: AssemblyFileVersion("1.0.9.0")] \ No newline at end of file diff --git a/README.md b/README.md index aef3cdf..2bb1386 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ The `JsonUtils` supports the following .NET types for serialization and deserial - Tuples (for instance: `(T1,T2)`) - Collections implementing `IEnumerable` interface (for instance: `List`, `T[]`, etc.) - Dictionaries implementing `IDictionary` interface (for instance: `Dictionary`) +- `HashSet` - Any custom user types (`class`, `struct`) with public properties and/or fields Please, be aware that the library will attempt to serialize public properties and fields of your custom types.