diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Node/JsonValueConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Node/JsonValueConverter.cs index b912ed898b42bd..92ffb3f5f70858 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Node/JsonValueConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Node/JsonValueConverter.cs @@ -27,6 +27,18 @@ public override void Write(Utf8JsonWriter writer, JsonValue? value, JsonSerializ return null; } + // For Object or Array types, return a JsonObject or JsonArray instance + // when deserializing a JsonValue. This maintains compatibility with .NET 8.0. + if (reader.TokenType is JsonTokenType.StartObject) + { + return JsonNodeConverter.ObjectConverter.Read(ref reader, typeof(JsonObject), options) as JsonValue; + } + + if (reader.TokenType is JsonTokenType.StartArray) + { + return JsonNodeConverter.ArrayConverter.Read(ref reader, typeof(JsonArray), options) as JsonValue; + } + JsonElement element = JsonElement.ParseValue(ref reader); return JsonValue.CreateFromElement(ref element, options.GetNodeOptions()); } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonValueTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonValueTests.cs index 29ae9662eedd4b..ce1518e3ac5a5d 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonValueTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonValueTests.cs @@ -626,5 +626,77 @@ public static IEnumerable GetPrimitiveTypes() #endif static object[] Wrap(T value, JsonValueKind expectedKind) => [value, expectedKind]; } + + [Fact] + public static void DeserializeArrayInDictionary_JsonValue_Works() + { + string json = """ + { "names": ["Chuck"] } + """; + + Dictionary dict = JsonSerializer.Deserialize>(json); + Assert.NotNull(dict); + Assert.True(dict.ContainsKey("names")); + Assert.NotNull(dict["names"]); + Assert.Equal(JsonValueKind.Array, dict["names"].GetValueKind()); + + // Also validate we can correctly get the content + string arrayValue = dict["names"].ToString(); + Assert.Contains("Chuck", arrayValue); + } + + [Fact] + public static void DeserializeObjectInDictionary_JsonValue_Works() + { + string json = """ + { "person": {"name": "Chuck"} } + """; + + Dictionary dict = JsonSerializer.Deserialize>(json); + Assert.NotNull(dict); + Assert.True(dict.ContainsKey("person")); + Assert.NotNull(dict["person"]); + Assert.Equal(JsonValueKind.Object, dict["person"].GetValueKind()); + + // Also validate we can correctly get the content + string objectValue = dict["person"].ToString(); + Assert.Contains("Chuck", objectValue); + } + + [Fact] + public static void Issue113268_JsonValueHandlesArraysAndObjects() + { + // This test specifically covers the issue reported in dotnet/runtime#113268 + // where deserialization of Dictionary containing arrays + // failed in .NET 9.0 but worked in .NET 8.0 + + string json = """ + { "names": ["Chuck"] } + """; + + Dictionary dict = JsonSerializer.Deserialize>(json); + Assert.NotNull(dict); + Assert.True(dict.ContainsKey("names")); + + // The key issue is that this line would throw in .NET 9.0 before the fix + JsonValue jsonValue = dict["names"]; + Assert.NotNull(jsonValue); + + // Additional validation + Assert.Equal(JsonValueKind.Array, jsonValue.GetValueKind()); + + // Test with an object too + json = """ + { "person": {"name": "Chuck"} } + """; + + dict = JsonSerializer.Deserialize>(json); + Assert.NotNull(dict); + Assert.True(dict.ContainsKey("person")); + + jsonValue = dict["person"]; + Assert.NotNull(jsonValue); + Assert.Equal(JsonValueKind.Object, jsonValue.GetValueKind()); + } } }