Skip to content

Polymorphic deserialization of object #121470

@MiloszKrajewski

Description

@MiloszKrajewski

I'm in between two third-party libraries, one is defining some hierarchy of classes, let's say, A, B and C, the other one does stuff and has pluggable serialization.

I'm trying to use System.Text.Json as a serializer but...

Third party library is serializing my data as List<object> and when they go in as A, B, and C they all come out on the other side as JsonElement.

I tried to configure polymorphic serialization using JsonSerializationOptions and it works just fine for hierarchies until declared serialized type is object. Then everything becomes JsonElement.

#pragma warning disable IL2026
#pragma warning disable IL3050

using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;

var jsonSettings = new JsonSerializerOptions {
    IncludeFields = true,
    TypeInfoResolver = new DefaultJsonTypeInfoResolver().WithAddedModifier(AddAbcHierarchy<A>),
};

var c = new C { Id = 1, Price = 9.99 };

var json1 = JsonSerializer.Serialize<A>(c, jsonSettings);
Console.WriteLine(json1);
var obj1 = JsonSerializer.Deserialize<A>(json1, jsonSettings);
Console.WriteLine(obj1?.GetType().Name);

var json2 = JsonSerializer.Serialize<object>(c, jsonSettings);
Console.WriteLine(json2);
var obj2 = JsonSerializer.Deserialize<object>(json2, jsonSettings);
Console.WriteLine(obj2?.GetType().Name);
return;

static void AddAbcHierarchy<TBase>(JsonTypeInfo jsonTypeInfo)
{
    if (jsonTypeInfo.Type == typeof(TBase))
    {
        var polymorphismOptions = new JsonPolymorphismOptions {
            TypeDiscriminatorPropertyName = "$type",
            IgnoreUnrecognizedTypeDiscriminators = false,
            UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType,
        };
        var deriveTypes = polymorphismOptions.DerivedTypes;
        deriveTypes.Add(new JsonDerivedType(typeof(A), "A"));
        deriveTypes.Add(new JsonDerivedType(typeof(B), "B"));
        deriveTypes.Add(new JsonDerivedType(typeof(C), "C"));
        jsonTypeInfo.PolymorphismOptions = polymorphismOptions;
    }
}

class A { public int Id; }
class B: A { public string? Description; }
class C: A { public double Price; }

In above example, C get serialized/deserialized as A and after deserialization it is correctly reported as C. When it gets serialized/deserialized as object then it is not longer C it is just JsonElement:

{"$type":"C","Price":9.99,"Id":1}
C
{"$type":"C","Price":9.99,"Id":1}
JsonElement

NOTE: I understand why it doesn't work, but the question is different: can I make it work at all? is polymorphic serialization possible if declared type is object?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions