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?