Skip to content

Commit

Permalink
Fix regression when serializing untyped polymorphic root-level custom…
Browse files Browse the repository at this point in the history
… converters. (#77186)

Fix #77173.
  • Loading branch information
eiriktsarpalis authored Oct 19, 2022
1 parent bd7e1cb commit 5ef4c68
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -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<T>
Expand Down Expand Up @@ -58,7 +56,7 @@ public partial class JsonConverter<T>
}
}

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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,5 +278,64 @@ public override void Write(Utf8JsonWriter writer, IRepro<object> 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<PolymorphicBaseClassConverter>(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<DerivedClass>("{}", options);
Assert.IsType<DerivedClass>(result);

object objResult = JsonSerializer.Deserialize("{}", typeof(DerivedClass), options);
Assert.IsType<DerivedClass>(objResult);

PocoWithDerivedClassProperty pocoResult = JsonSerializer.Deserialize<PocoWithDerivedClassProperty>("""{"Value":{}}""", options);
Assert.IsType<DerivedClass>(pocoResult.Value);

DerivedClass[] arrayResult = JsonSerializer.Deserialize<DerivedClass[]>("[{}]", options);
Assert.IsType<DerivedClass>(arrayResult[0]);

Dictionary<string, DerivedClass> dictResult = JsonSerializer.Deserialize<Dictionary<string, DerivedClass>>("""{"Value":{}}""", options);
Assert.IsType<DerivedClass>(dictResult["Value"]);
}

public class BaseClass
{ }

public class DerivedClass : BaseClass
{ }

public class PocoWithDerivedClassProperty
{
public DerivedClass Value { get; set; }
}

public class PolymorphicBaseClassConverter : JsonConverter<BaseClass>
{
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();
}
}
}
}

0 comments on commit 5ef4c68

Please sign in to comment.