DictionaryKeyPolicy not applied to keys that contain non primitive ty… (dotnet/corefx...
authormarcnet80 <46241368+marcnet80@users.noreply.github.com>
Thu, 14 Nov 2019 00:49:54 +0000 (02:49 +0200)
committerDavid Cantu <dacantu@microsoft.com>
Thu, 14 Nov 2019 00:49:54 +0000 (16:49 -0800)
* DictionaryKeyPolicy not applied to keys that contain non primitive types dotnet/corefx#41176

https://github.com/dotnet/corefx/issues/41176#event-2697607085

* dotnet/corefx#41176: DictionaryKeyPolicy not applied to keys that contain non primitive types

https://github.com/dotnet/corefx/issues/41176

* add unit tests

https://github.com/dotnet/corefx/pull/41691

* Remove check for JsonExtensionDataAttribute to avoid reflection.

Commit migrated from https://github.com/dotnet/corefx/commit/d9dd0dac4285368002740333d6772d4db79d82c1

src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.HandleDictionary.cs
src/libraries/System.Text.Json/tests/Serialization/DictionaryTests.KeyPolicy.cs

index d39ea99..22c1f23 100644 (file)
@@ -81,8 +81,14 @@ namespace System.Text.Json
                         jsonPropertyInfo.GetDictionaryKeyAndValue(ref state.Current, out key, out value);
                     }
 
+                    if (options.DictionaryKeyPolicy != null && state.Current.ExtensionDataStatus != ExtensionDataWriteStatus.Writing)
+                    {
+                        key = options.DictionaryKeyPolicy.ConvertName(key);
+                    }
+
                     // An object or another enumerator requires a new stack frame.
                     state.Push(elementClassInfo, value);
+
                     state.Current.KeyName = key;
                 }
 
index 47f1595..05c7cbe 100644 (file)
@@ -258,5 +258,147 @@ namespace System.Text.Json.Serialization.Tests
             // Check that we write all.
             Assert.Equal(@"{""myInt"":1,""myInt"":2}", json);
         }
+        
+        [Fact]
+        public static void CamelCaseSerialize_ApplyDictionaryKeyPolicy()
+        {
+            const string JsonCamel = @"{""keyDict"":{""keyString"":""text"",""keyNumber"":1000,""keyBool"":true},""keyList"":[1,2,3]}";
+            var options = new JsonSerializerOptions
+            {
+                DictionaryKeyPolicy = JsonNamingPolicy.CamelCase
+            };
+            
+            var obj = new Dictionary<string, object>();
+            obj["KeyDict"] = new Dictionary<string, object>()
+            {
+                { "KeyString", "text" },
+                { "KeyNumber", 1000 },
+                { "KeyBool", true }
+            };
+            obj["KeyList"] = new List<int>() { 1, 2, 3 };
+            
+            var json = JsonSerializer.Serialize(obj, new JsonSerializerOptions()
+            {
+                DictionaryKeyPolicy = JsonNamingPolicy.CamelCase
+            });
+            
+            Assert.Equal(JsonCamel, json);
+        }
+        
+        [Fact]
+        public static void SerializationWithJsonExtensionDataAttribute_IgoneDictionaryKeyPolicy()
+        {
+            var expectedJson = @"{""KeyInt"":1000,""KeyString"":""text"",""KeyBool"":true,""KeyObject"":{},""KeyList"":[],""KeyDictionary"":{}}";
+            var obj = new ClassWithExtensionDataProperty();
+            obj.Data = new Dictionary<string, object>()
+            {
+                { "KeyInt", 1000 },
+                { "KeyString", "text" },
+                { "KeyBool", true },
+                { "KeyObject", new object() },
+                { "KeyList", new List<string>() },
+                { "KeyDictionary", new Dictionary<string, string>() }
+            };
+            string json = JsonSerializer.Serialize(obj, new JsonSerializerOptions()
+            {
+                DictionaryKeyPolicy = JsonNamingPolicy.CamelCase
+            });
+            Assert.Equal(expectedJson, json);
+        }
+
+        private class ClassWithExtensionDataProperty
+        {
+           [JsonExtensionData]
+            public Dictionary<string, object> Data { get; set; }
+        }
+        
+        [Fact]
+        public static void CamelCaseSerialize_ForTypedDictionary_ApplyDictionaryKeyPolicy()
+        {
+            const string JsonCamel = @"{""keyDict"":{""Name"":""text"",""Number"":1000,""isValid"":true,""Values"":[1,2,3]}}";
+            var obj = new Dictionary<string, CustomClass>()
+            {
+                { "KeyDict", CreateCustomObject() }
+            };
+            var json = JsonSerializer.Serialize(obj, new JsonSerializerOptions()
+            {
+                DictionaryKeyPolicy = JsonNamingPolicy.CamelCase
+            });
+
+            Assert.Equal(JsonCamel, json);
+        }
+
+        private class CustomClass
+        {
+            public string Name { get; set; }
+            public int Number { get; set; }
+            public bool isValid { get; set; }
+            public List<int> Values { get; set; }
+        }
+        
+        private static CustomClass CreateCustomObject()
+        {
+            return new CustomClass { Name = "text", Number = 1000, isValid = true, Values = new List<int>() { 1, 2, 3 } };
+        }
+
+        [Fact]
+        public static void CamelCaseSerialize_ForNestedTypedDictionary_ApplyDictionaryKeyPolicy()
+        {
+            const string JsonCamel = @"{""keyDict"":{""nestedKeyDict"":{""Name"":""text"",""Number"":1000,""isValid"":true,""Values"":[1,2,3]}}}";
+            var options = new JsonSerializerOptions
+            {
+                DictionaryKeyPolicy = JsonNamingPolicy.CamelCase
+            };
+            var obj = new Dictionary<string, Dictionary<string, CustomClass>>(){
+                { "KeyDict", new  Dictionary<string,CustomClass>()
+                {{ "NestedKeyDict", CreateCustomObject() }}
+            }};
+            var json = JsonSerializer.Serialize(obj, new JsonSerializerOptions()
+            {
+                DictionaryKeyPolicy = JsonNamingPolicy.CamelCase
+            });
+
+            Assert.Equal(JsonCamel, json);
+        }
+
+        private class TestClassWithDictionary
+        {
+           public Dictionary<string, CustomClass> Data { get; set; }
+               }
+
+        [Fact]
+        public static void CamelCaseSerialize_ForClassWithDictionaryProperty_ApplyDictionaryKeyPolicy()
+        {
+            const string JsonCamel = @"{""Data"":{""keyObj"":{""Name"":""text"",""Number"":1000,""isValid"":true,""Values"":[1,2,3]}}}";
+            var obj = new TestClassWithDictionary();
+            obj.Data = new Dictionary<string, CustomClass> {
+                {"KeyObj", CreateCustomObject() }
+            };
+            var json = JsonSerializer.Serialize(obj, new JsonSerializerOptions()
+            {
+                DictionaryKeyPolicy = JsonNamingPolicy.CamelCase
+            });
+            Assert.Equal(JsonCamel, json);
+        }
+
+        [Fact]
+        public static void CamelCaseSerialize_ForKeyValuePairWithDictionaryValue_ApplyDictionaryKeyPolicy()
+        {
+            const string JsonCamel = @"{""Key"":""KeyPair"",""Value"":{""keyDict"":{""Name"":""text"",""Number"":1000,""isValid"":true,""Values"":[1,2,3]}}}";
+            var options = new JsonSerializerOptions
+            {
+                DictionaryKeyPolicy = JsonNamingPolicy.CamelCase
+            };
+            var obj = new KeyValuePair<string, Dictionary<string, CustomClass>>
+              ("KeyPair", new Dictionary<string, CustomClass> {
+              {"KeyDict", CreateCustomObject() }
+            });
+            var json = JsonSerializer.Serialize(obj, new JsonSerializerOptions()
+            {
+                DictionaryKeyPolicy = JsonNamingPolicy.CamelCase
+            });
+
+            Assert.Equal(JsonCamel, json);
+        }
     }
 }