I have an abstract base class:
[JsonConverter(typeof(Converter))]
public abstract class TextComponent {
...
public bool Bold { get; set; }
public TextComponent[] Extra { get; set; }
...
}
And more classes which inherits from it. One of those classes is StringComponent
:
public sealed class StringComponent : TextComponent
{
public string Text { get; set; }
public StringComponent(string text)
{
Text = text;
}
}
Converter
, which is a JsonConverter
applied to TextComponent
looks like this:
private sealed class Converter : JsonConverter
{
....
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
var tok = JToken.Load(reader);
switch (tok)
{
...
case JObject x:
var dic = (IDictionary<string, JToken>) x;
if (dic.ContainsKey("text")) return x.ToObject<StringComponent>();
...
...
}
}
...
public override bool CanConvert(Type objectType) => objectType == typeof(TextComponent);
}
The problem:
var str = "{\"text\":\"hello world\"}";
var obj = JsonConvert.DeserializeObject<TextComponent>(str);
// this doesn't work either:
var obj = JsonConvert.DeserializeObject<StringComponent>(str);
This goes into an infinite "loop" eventually resulting in a StackOverflow
, because when calling DeserializeObject<Stringcomponent>
or ToObject<StringComponent>
, the JsonConverter
of the base class (the Converter
) is used which again calls those methods. This is not the desired behavior. When serializing derived classes, they should not be using base class's JsonConverter
. If you look at CanConvert
method of the Converter
, I'm also only allowing it for TextComponent
only, not for any of it's derived classes.
So how do I fix this?