From 799a2ee052dfc1d529d4a186c9e24e5f3c192fcc Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Wed, 19 Oct 2022 00:00:51 +0100 Subject: [PATCH] Fix regression when serializing untyped polymorphic root-level custom converters. Fix #77173. --- .../JsonConverterOfT.ReadCore.cs | 4 +- .../CustomConverterTests.Polymorphic.cs | 59 +++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.ReadCore.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.ReadCore.cs index df4963e3b6ef23..975df8ae20227e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.ReadCore.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.ReadCore.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Text.Json.Serialization.Metadata; - namespace System.Text.Json.Serialization { public partial class JsonConverter @@ -58,7 +56,7 @@ public partial class JsonConverter } } - bool success = TryRead(ref reader, TypeToConvert, options, ref state, out T? value); + bool success = TryRead(ref reader, state.Current.JsonTypeInfo.Type, options, ref state, out T? value); if (success) { // Read any trailing whitespace. This will throw if JsonCommentHandling=Disallow. diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CustomConverterTests/CustomConverterTests.Polymorphic.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CustomConverterTests/CustomConverterTests.Polymorphic.cs index e61319e55caa14..cbf48b487946ee 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CustomConverterTests/CustomConverterTests.Polymorphic.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CustomConverterTests/CustomConverterTests.Polymorphic.cs @@ -278,5 +278,64 @@ public override void Write(Utf8JsonWriter writer, IRepro value, JsonSeri } } } + + [Fact] + public static void PolymorphicBaseClassConverter_IsPassedCorrectTypeToConvertParameter() + { + // Regression test for https://github.com/dotnet/runtime/issues/77173 + var options = new JsonSerializerOptions { Converters = { new PolymorphicBaseClassConverter() } }; + + // Sanity check -- returns converter for the base class. + JsonConverter converter = options.GetConverter(typeof(DerivedClass)); + Assert.IsAssignableFrom(converter); + + // Validate that the correct typeToConvert parameter is passed in all serialization contexts: + // 1. Typed root value. + // 2. Untyped root value (where the reported regression occured). + // 3. Nested values in POCOs, collections & dictionaries. + + DerivedClass result = JsonSerializer.Deserialize("{}", options); + Assert.IsType(result); + + object objResult = JsonSerializer.Deserialize("{}", typeof(DerivedClass), options); + Assert.IsType(objResult); + + PocoWithDerivedClassProperty pocoResult = JsonSerializer.Deserialize("""{"Value":{}}""", options); + Assert.IsType(pocoResult.Value); + + DerivedClass[] arrayResult = JsonSerializer.Deserialize("[{}]", options); + Assert.IsType(arrayResult[0]); + + Dictionary dictResult = JsonSerializer.Deserialize>("""{"Value":{}}""", options); + Assert.IsType(dictResult["Value"]); + } + + public class BaseClass + { } + + public class DerivedClass : BaseClass + { } + + public class PocoWithDerivedClassProperty + { + public DerivedClass Value { get; set; } + } + + public class PolymorphicBaseClassConverter : JsonConverter + { + public override bool CanConvert(Type typeToConvert) => typeof(BaseClass).IsAssignableFrom(typeToConvert); + + public override BaseClass? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + Assert.Equal(typeof(DerivedClass), typeToConvert); + reader.Skip(); + return (BaseClass)Activator.CreateInstance(typeToConvert); + } + + public override void Write(Utf8JsonWriter writer, BaseClass value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } + } } }