Providing support for duplicate keys in dictionary (dotnet/corefx#38524)
authorAnirudh Agnihotry <anirudhagnihotry098@gmail.com>
Mon, 17 Jun 2019 22:48:41 +0000 (15:48 -0700)
committerGitHub <noreply@github.com>
Mon, 17 Jun 2019 22:48:41 +0000 (15:48 -0700)
* providing support for duplicate keys in dictionary

* Improving failure message

* fixing merge conflicts

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

src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleArray.cs
src/libraries/System.Text.Json/tests/Serialization/DictionaryTests.cs
src/libraries/System.Text.Json/tests/Serialization/ExceptionTests.cs

index 04bd680..b7ac54a 100644 (file)
@@ -198,14 +198,7 @@ namespace System.Text.Json
 
                 string key = state.Current.KeyName;
                 Debug.Assert(!string.IsNullOrEmpty(key));
-                if (!dictionary.Contains(key))
-                {
-                    dictionary.Add(key, value);
-                }
-                else
-                {
-                    ThrowHelper.ThrowJsonException_DeserializeDuplicateKey(key, reader, state.JsonPath);
-                }
+                dictionary[key] = value;
             }
             else if (state.Current.IsIDictionaryConstructible ||
                 (state.Current.IsIDictionaryConstructibleProperty && !setPropertyDirectly) ||
@@ -217,14 +210,7 @@ namespace System.Text.Json
 
                 string key = state.Current.KeyName;
                 Debug.Assert(!string.IsNullOrEmpty(key));
-                if (!dictionary.Contains(key))
-                {
-                    dictionary.Add(key, value);
-                }
-                else
-                {
-                    ThrowHelper.ThrowJsonException_DeserializeDuplicateKey(key, reader, state.JsonPath);
-                }
+                dictionary[key] = value;
             }
             else
             {
@@ -280,14 +266,7 @@ namespace System.Text.Json
 
                 string key = state.Current.KeyName;
                 Debug.Assert(!string.IsNullOrEmpty(key));
-                if (!dictionary.ContainsKey(key)) // The IDictionary.TryAdd extension method is not available in netstandard.
-                {
-                    dictionary.Add(key, value);
-                }
-                else
-                {
-                    ThrowHelper.ThrowJsonException_DeserializeDuplicateKey(key, reader, state.JsonPath);
-                }
+                dictionary[key] = value;
             }
             else if (state.Current.IsProcessingIDictionaryConstructibleOrKeyValuePair)
             {
@@ -296,14 +275,7 @@ namespace System.Text.Json
 
                 string key = state.Current.KeyName;
                 Debug.Assert(!string.IsNullOrEmpty(key));
-                if (!dictionary.ContainsKey(key)) // The IDictionary.TryAdd extension method is not available in netstandard.
-                {
-                    dictionary.Add(key, value);
-                }
-                else
-                {
-                    ThrowHelper.ThrowJsonException_DeserializeDuplicateKey(key, reader, state.JsonPath);
-                }
+                dictionary[key] = value;
             }
             else
             {
index 6efcfdf..590d580 100644 (file)
@@ -140,22 +140,6 @@ namespace System.Text.Json.Serialization.Tests
         }
 
         [Fact]
-        public static void DuplicateKeysFail()
-        {
-            // Non-generic IDictionary case.
-            Assert.Throws<JsonException>(() => JsonSerializer.Parse<IDictionary>(
-                @"{""Hello"":""World"", ""Hello"":""World""}"));
-
-            // Strongly-typed IDictionary<,> case.
-            Assert.Throws<JsonException>(() => JsonSerializer.Parse<Dictionary<string, string>>(
-                @"{""Hello"":""World"", ""Hello"":""World""}"));
-
-            // Weakly-typed IDictionary case.
-            Assert.Throws<JsonException>(() => JsonSerializer.Parse<Dictionary<string, object>>(
-                @"{""Hello"":null, ""Hello"":null}"));
-        }
-
-        [Fact]
         public static void DictionaryOfObject()
         {
             {
@@ -790,6 +774,21 @@ namespace System.Text.Json.Serialization.Tests
         }
 
         [Fact]
+        public static void DeserializeDictionaryWithDuplicateKeys()
+        {
+            // Strongly-typed IDictionary<,> case.
+            Dictionary<string, string> deserialize = JsonSerializer.Parse<Dictionary<string, string>>(@"{""Hello"":""World"", ""Hello"":""NewValue""}");
+            Assert.Equal("NewValue", deserialize["Hello"]);
+
+            deserialize = JsonSerializer.Parse<Dictionary<string, string>>(@"{""Hello"":""World"", ""myKey"" : ""myValue"", ""Hello"":""NewValue""}");
+            Assert.Equal("NewValue", deserialize["Hello"]);
+
+            // Weakly-typed IDictionary case.
+            Dictionary<string, object> deserializeObject = JsonSerializer.Parse<Dictionary<string, object>>(@"{""Hello"":""World"", ""Hello"": null}");
+            Assert.Null(deserializeObject["Hello"]);
+        }
+
+        [Fact]
         public static void ClassWithNoSetter()
         {
             string json = @"{""MyDictionary"":{""Key"":""Value""}}";
index c909971..3bbeb0c 100644 (file)
@@ -34,14 +34,14 @@ namespace System.Text.Json.Serialization.Tests
         {
             try
             {
-                JsonSerializer.Parse<IDictionary<string, int>>(@"{""Key"":1, ""Key"":2}");
-                Assert.True(false, "Expected JsonException was not thrown.");
+                JsonSerializer.Parse<IDictionary<string, string>>(@"{""Key"":1, ""Key"":2}");
+                Assert.True(false, "We follow 'Last value wins' approach for duplicate keys.");
             }
             catch (JsonException e)
             {
                 Assert.Equal(0, e.LineNumber);
-                Assert.Equal(17, e.BytePositionInLine);
-                Assert.Contains("LineNumber: 0 | BytePositionInLine: 17.", e.Message);
+                Assert.Equal(8, e.BytePositionInLine);
+                Assert.Contains("LineNumber: 0 | BytePositionInLine: 8.", e.Message);
                 Assert.Contains("$.Key", e.Path);
 
                 // Verify Path is not repeated.