From aa9e9f97f8988f2c2c5540470414ef38957d59b9 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Wed, 19 Oct 2022 00:00:51 +0100 Subject: [PATCH 1/2] 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(); + } + } } } From 477f4e9994bf9ebe1927b2f3263dc0995d71e18f Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Mon, 24 Oct 2022 18:35:56 +0100 Subject: [PATCH 2/2] Update servicing version --- src/libraries/System.Text.Json/src/System.Text.Json.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj index f0341a109304e8..654dfdc855c999 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -8,6 +8,8 @@ CS8969 true true + true + 1 true Provides high-performance and low-allocating types that serialize objects to JavaScript Object Notation (JSON) text and deserialize JSON text to objects, with UTF-8 support built-in. Also provides types to read and write JSON text encoded as UTF-8, and to create an in-memory document object model (DOM), that is read-only, for random access of the JSON elements within a structured view of the data.