diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfo.cs index 500a0f35bbb0cf..2a97240d67b976 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfo.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonPropertyInfo.cs @@ -368,57 +368,56 @@ internal bool ReadJsonAndAddExtensionProperty( { object propValue = GetValueAsObject(obj)!; - if (propValue is IDictionary dictionaryObject) + if (propValue is IDictionary dictionaryObjectValue) { - // Handle case where extension property is System.Object-based. - if (reader.TokenType == JsonTokenType.Null) { // A null JSON value is treated as a null object reference. - dictionaryObject[state.Current.JsonPropertyNameAsString!] = null; + dictionaryObjectValue[state.Current.JsonPropertyNameAsString!] = null; } else { - JsonConverter converter; - JsonTypeInfo? dictionaryValueInfo = RuntimeTypeInfo.ElementTypeInfo; - if (dictionaryValueInfo != null) - { - // Fast path when there is a generic type such as Dictionary. - converter = dictionaryValueInfo.PropertyInfoForTypeInfo.ConverterBase; - } - else - { - // Slower path for non-generic types that implement IDictionary. - converter = JsonMetadataServices.ObjectConverter; - } - - if (!converter.TryReadAsObject(ref reader, Options, ref state, out object? value)) - { - return false; - } - - dictionaryObject[state.Current.JsonPropertyNameAsString!] = value; + JsonConverter converter = (JsonConverter)GetDictionaryValueConverter(JsonTypeInfo.ObjectType); + object value = converter.Read(ref reader, JsonTypeInfo.ObjectType, Options)!; + dictionaryObjectValue[state.Current.JsonPropertyNameAsString!] = value; } } - else if (propValue is IDictionary dictionaryJsonElement) + else if (propValue is IDictionary dictionaryElementValue) { - JsonConverter converter = JsonMetadataServices.JsonElementConverter; - if (!converter.TryRead(ref reader, typeof(JsonElement), Options, ref state, out JsonElement value)) - { - return false; - } - - dictionaryJsonElement[state.Current.JsonPropertyNameAsString!] = value; + Type elementType = typeof(JsonElement); + JsonConverter converter = (JsonConverter)GetDictionaryValueConverter(elementType); + JsonElement value = converter.Read(ref reader, elementType, Options); + dictionaryElementValue[state.Current.JsonPropertyNameAsString!] = value; } else { // Avoid a type reference to JsonObject and its converter to support trimming. Debug.Assert(propValue is Nodes.JsonObject); - ConverterBase.ReadElementAndSetProperty(propValue, state.Current.JsonPropertyNameAsString!, ref reader, Options, ref state); } return true; + + JsonConverter GetDictionaryValueConverter(Type dictionaryValueType) + { + JsonConverter converter; + JsonTypeInfo? dictionaryValueInfo = RuntimeTypeInfo.ElementTypeInfo; + if (dictionaryValueInfo != null) + { + // Fast path when there is a generic type such as Dictionary<,>. + converter = dictionaryValueInfo.PropertyInfoForTypeInfo.ConverterBase; + } + else + { + // Slower path for non-generic types that implement IDictionary<,>. + // It is possible to cache this converter on JsonTypeInfo if we assume the property value + // will always be the same type for all instances. + converter = Options.GetConverterInternal(dictionaryValueType); + } + + Debug.Assert(converter != null); + return converter; + } } internal abstract bool ReadJsonAndSetMember(object obj, ref ReadStack state, ref Utf8JsonReader reader); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/ExtensionDataTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/ExtensionDataTests.cs index f7e0243a5492c8..853ec365189827 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/ExtensionDataTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/ExtensionDataTests.cs @@ -1239,7 +1239,7 @@ public static void CustomJsonElementConverterInExtensionProperty() ClassWithExtensionPropertyAsJsonElement obj = JsonSerializer.Deserialize(Json, options); JsonElement overflowProp = obj.MyOverflow["hello"]; - Assert.Equal(JsonValueKind.String, overflowProp.ValueKind); + Assert.Equal(JsonValueKind.Undefined, overflowProp.ValueKind); string newJson = JsonSerializer.Serialize(obj, options); Assert.Equal("{\"hello\":{\"Hi\":\"There\"}}", newJson);