From: Layomi Akinrinade Date: Sun, 16 Jun 2019 10:57:34 +0000 (-0400) Subject: Add support for serializing types that implement IDictionary (dotnet... X-Git-Tag: submit/tizen/20210909.063632~11031^2~1272 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c5a7b1cb663917d2621f153ad2a39f9964616293;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Add support for serializing types that implement IDictionary (dotnet/corefx#38512) * Add support for serializing types that implement IDictionary * Add test for string to string IDictionary * fixup * Address review feedback * Rename dict -> dictionary Commit migrated from https://github.com/dotnet/corefx/commit/e2e5fb23280b3962dcb0422b0df7930387c8ac24 --- diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.AddProperty.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.AddProperty.cs index 3c535a4..9a00e5b 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.AddProperty.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.AddProperty.cs @@ -29,14 +29,13 @@ namespace System.Text.Json // Convert non-immutable dictionary interfaces to concrete types. if (propertyType.IsInterface && jsonInfo.ClassType == ClassType.Dictionary) { - // If a polymorphic case, we have to wait until run-time values are processed. - if (jsonInfo.ElementClassInfo.ClassType != ClassType.Unknown || propertyType == typeof(IDictionary)) + JsonClassInfo elementClassInfo = jsonInfo.ElementClassInfo; + JsonPropertyInfo elementPropertyInfo = options.GetJsonPropertyInfoFromClassInfo(elementClassInfo, options); + + Type newPropertyType = elementPropertyInfo.GetDictionaryConcreteType(); + if (propertyType != newPropertyType) { - Type newPropertyType = jsonInfo.ElementClassInfo.GetPolicyProperty().GetDictionaryConcreteType(); - if (propertyType != newPropertyType) - { - jsonInfo = CreateProperty(propertyType, newPropertyType, propertyInfo, classType, options); - } + jsonInfo = CreateProperty(propertyType, newPropertyType, propertyInfo, classType, options); } } else if (jsonInfo.ClassType == ClassType.Enumerable && diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.HandleDictionary.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.HandleDictionary.cs index 91b6bdb..7fc3a9d 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.HandleDictionary.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.HandleDictionary.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; @@ -31,7 +30,15 @@ namespace System.Text.Json return true; } - state.Current.Enumerator = ((IDictionary)enumerable).GetEnumerator(); + if (enumerable is IDictionary dictionary) + { + state.Current.Enumerator = dictionary.GetEnumerator(); + } + else + { + state.Current.Enumerator = enumerable.GetEnumerator(); + } + state.Current.WriteObjectOrArrayStart(ClassType.Dictionary, writer); } diff --git a/src/libraries/System.Text.Json/tests/Serialization/DictionaryTests.cs b/src/libraries/System.Text.Json/tests/Serialization/DictionaryTests.cs index 544c24b..6efcfdf 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/DictionaryTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/DictionaryTests.cs @@ -5,6 +5,7 @@ using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; +using Newtonsoft.Json; using Xunit; namespace System.Text.Json.Serialization.Tests @@ -158,7 +159,7 @@ namespace System.Text.Json.Serialization.Tests public static void DictionaryOfObject() { { - IDictionary obj = JsonSerializer.Parse(@"{""Key1"":1}"); + Dictionary obj = JsonSerializer.Parse>(@"{""Key1"":1}"); Assert.Equal(1, obj.Count); JsonElement element = (JsonElement)obj["Key1"]; Assert.Equal(JsonValueType.Number, element.Type); @@ -169,7 +170,7 @@ namespace System.Text.Json.Serialization.Tests } { - Dictionary obj = JsonSerializer.Parse>(@"{""Key1"":1}"); + IDictionary obj = JsonSerializer.Parse>(@"{""Key1"":1}"); Assert.Equal(1, obj.Count); JsonElement element = (JsonElement)obj["Key1"]; Assert.Equal(JsonValueType.Number, element.Type); @@ -180,6 +181,42 @@ namespace System.Text.Json.Serialization.Tests } } + [Fact] + public static void ImplementsIDictionaryOfObject() + { + var input = new StringToObjectIDictionaryWrapper(new Dictionary + { + { "Name", "David" }, + { "Age", 32 } + }); + + string json = JsonSerializer.ToString(input, typeof(IDictionary)); + Assert.Equal(@"{""Name"":""David"",""Age"":32}", json); + + IDictionary obj = JsonSerializer.Parse>(json); + Assert.Equal(2, obj.Count); + Assert.Equal("David", ((JsonElement)obj["Name"]).GetString()); + Assert.Equal(32, ((JsonElement)obj["Age"]).GetInt32()); + } + + [Fact] + public static void ImplementsIDictionaryOfString() + { + var input = new StringToStringIDictionaryWrapper(new Dictionary + { + { "Name", "David" }, + { "Job", "Software Architect" } + }); + + string json = JsonSerializer.ToString(input, typeof(IDictionary)); + Assert.Equal(@"{""Name"":""David"",""Job"":""Software Architect""}", json); + + IDictionary obj = JsonSerializer.Parse>(json); + Assert.Equal(2, obj.Count); + Assert.Equal("David", obj["Name"]); + Assert.Equal("Software Architect", obj["Job"]); + } + [Theory] [InlineData(typeof(ImmutableDictionary), "\"headers\"")] [InlineData(typeof(Dictionary), "\"headers\"")] @@ -790,7 +827,7 @@ namespace System.Text.Json.Serialization.Tests public static void DeserializeUserDefinedDictionaryThrows() { string json = @"{""Hello"":1,""Hello2"":2}"; - Assert.Throws(() => JsonSerializer.Parse(json)); + Assert.Throws(() => JsonSerializer.Parse(json)); } public class ClassWithDictionaryButNoSetter @@ -807,81 +844,5 @@ namespace System.Text.Json.Serialization.Tests { [JsonIgnore] public Dictionary MyDictionary { get; set; } } - - public class UserDefinedImmutableDictionary : IImmutableDictionary - { - public int this[string key] => throw new NotImplementedException(); - - public IEnumerable Keys => throw new NotImplementedException(); - - public IEnumerable Values => throw new NotImplementedException(); - - public int Count => throw new NotImplementedException(); - - public IImmutableDictionary Add(string key, int value) - { - throw new NotImplementedException(); - } - - public IImmutableDictionary AddRange(IEnumerable> pairs) - { - throw new NotImplementedException(); - } - - public IImmutableDictionary Clear() - { - throw new NotImplementedException(); - } - - public bool Contains(KeyValuePair pair) - { - throw new NotImplementedException(); - } - - public bool ContainsKey(string key) - { - throw new NotImplementedException(); - } - - public IEnumerator> GetEnumerator() - { - throw new NotImplementedException(); - } - - public IImmutableDictionary Remove(string key) - { - throw new NotImplementedException(); - } - - public IImmutableDictionary RemoveRange(IEnumerable keys) - { - throw new NotImplementedException(); - } - - public IImmutableDictionary SetItem(string key, int value) - { - throw new NotImplementedException(); - } - - public IImmutableDictionary SetItems(IEnumerable> items) - { - throw new NotImplementedException(); - } - - public bool TryGetKey(string equalKey, out string actualKey) - { - throw new NotImplementedException(); - } - - public bool TryGetValue(string key, out int value) - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - } } } diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.Dictionary.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses.Dictionary.cs new file mode 100644 index 0000000..a18efbb --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/TestClasses.Dictionary.cs @@ -0,0 +1,236 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections; +using System.Collections.Generic; +using System.Collections.Immutable; + +namespace System.Text.Json.Serialization.Tests +{ + public class IImmutableDictionaryWrapper : IImmutableDictionary + { + public int this[string key] => throw new NotImplementedException(); + + public IEnumerable Keys => throw new NotImplementedException(); + + public IEnumerable Values => throw new NotImplementedException(); + + public int Count => throw new NotImplementedException(); + + public IImmutableDictionary Add(string key, int value) + { + throw new NotImplementedException(); + } + + public IImmutableDictionary AddRange(IEnumerable> pairs) + { + throw new NotImplementedException(); + } + + public IImmutableDictionary Clear() + { + throw new NotImplementedException(); + } + + public bool Contains(KeyValuePair pair) + { + throw new NotImplementedException(); + } + + public bool ContainsKey(string key) + { + throw new NotImplementedException(); + } + + public IEnumerator> GetEnumerator() + { + throw new NotImplementedException(); + } + + public IImmutableDictionary Remove(string key) + { + throw new NotImplementedException(); + } + + public IImmutableDictionary RemoveRange(IEnumerable keys) + { + throw new NotImplementedException(); + } + + public IImmutableDictionary SetItem(string key, int value) + { + throw new NotImplementedException(); + } + + public IImmutableDictionary SetItems(IEnumerable> items) + { + throw new NotImplementedException(); + } + + public bool TryGetKey(string equalKey, out string actualKey) + { + throw new NotImplementedException(); + } + + public bool TryGetValue(string key, out int value) + { + throw new NotImplementedException(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); + } + } + + public class StringToObjectIDictionaryWrapper : IDictionary + { + private readonly IDictionary _dict; + + public StringToObjectIDictionaryWrapper(IDictionary dict) + { + _dict = dict; + } + + public object this[string key] { get => _dict[key]; set => _dict[key] = value; } + + public ICollection Keys => _dict.Keys; + + public ICollection Values => _dict.Values; + + public int Count => _dict.Count; + + public bool IsReadOnly => false; + + public void Add(string key, object value) + { + _dict.Add(key, value); + } + + public void Add(KeyValuePair item) + { + _dict.Add(item.Key, item.Value); + } + + public void Clear() + { + _dict.Clear(); + } + + public bool Contains(KeyValuePair item) + { + return _dict.Contains(item); + } + + public bool ContainsKey(string key) + { + return _dict.ContainsKey(key); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + _dict.CopyTo(array, arrayIndex); + } + + public IEnumerator> GetEnumerator() + { + return _dict.GetEnumerator(); + } + + public bool Remove(string key) + { + return _dict.Remove(key); + } + + public bool Remove(KeyValuePair item) + { + return _dict.Remove(item); + } + + public bool TryGetValue(string key, out object value) + { + return _dict.TryGetValue(key, out value); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + + public class StringToStringIDictionaryWrapper : IDictionary + { + private readonly IDictionary _dict; + + public StringToStringIDictionaryWrapper(IDictionary dict) + { + _dict = dict; + } + + public string this[string key] { get => _dict[key]; set => _dict[key] = value; } + + public ICollection Keys => _dict.Keys; + + public ICollection Values => _dict.Values; + + public int Count => _dict.Count; + + public bool IsReadOnly => false; + + public void Add(string key, string value) + { + _dict.Add(key, value); + } + + public void Add(KeyValuePair item) + { + _dict.Add(item.Key, item.Value); + } + + public void Clear() + { + _dict.Clear(); + } + + public bool Contains(KeyValuePair item) + { + return _dict.Contains(item); + } + + public bool ContainsKey(string key) + { + return _dict.ContainsKey(key); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + _dict.CopyTo(array, arrayIndex); + } + + public IEnumerator> GetEnumerator() + { + return _dict.GetEnumerator(); + } + + public bool Remove(string key) + { + return _dict.Remove(key); + } + + public bool Remove(KeyValuePair item) + { + return _dict.Remove(item); + } + + public bool TryGetValue(string key, out string value) + { + return _dict.TryGetValue(key, out value); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj index 089f72c..ad1f641 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj @@ -53,6 +53,7 @@ +