-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
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?