Last active
February 17, 2023 23:16
-
-
Save chrisoldwood/b604d69543a5fe5896a94409058c7a95 to your computer and use it in GitHub Desktop.
Example showing infinite loop deserialising polymorphic types with a custom JsonConverter.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace JsonTests | |
{ | |
public class CustomJsonConverter : JsonConverter | |
{ | |
public override bool CanConvert(Type objectType) | |
{ | |
return typeof(BaseType).IsAssignableFrom(objectType); | |
} | |
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) | |
{ | |
JObject item = JObject.Load(reader); | |
#if USE_TO_OBJECT | |
var @object = item.ToObject<DerivedType>(); | |
return @object; | |
#else // USE_POPULATE | |
var @object = new DerivedType(); | |
serializer.Populate(item.CreateReader(), @object); | |
return @object; | |
#endif | |
} | |
public override bool CanWrite => false; | |
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) | |
{ | |
throw new NotImplementedException(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace JsonTests | |
{ | |
[JsonConverter(typeof(CustomJsonConverter))] | |
public abstract class BaseType | |
{ | |
public string Value { get; set; } | |
} | |
public class DerivedType : BaseType | |
{ | |
public string DerivedValue { get; set; } | |
} | |
public class Container | |
{ | |
public List<BaseType> Objects { get; set; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace JsonTests | |
{ | |
[TestFixture] | |
public class Tests | |
{ | |
[Test] | |
public void Test() | |
{ | |
const string json = | |
"{ 'Objects': [" + | |
" { 'Value': 'test value' } " + | |
"] }"; | |
#if USE_TO_OBJECT | |
Assert.That(() => JsonConvert.DeserializeObject<Container>(json), | |
Throws.InstanceOf<StackOverflowException>()); | |
#else // USE_POPULATE | |
Assert.That(() => JsonConvert.DeserializeObject<Container>(json), | |
Throws.Nothing); | |
#endif | |
} | |
} | |
} |
Thanks Chris, this was very helpful. I had an example where I was using the toObject method in JsonSerializerSettings and it worked so I was surprised when my new code used that method and was causing the stack overflow exception.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for the info. However, the stack overflow answers you cite did not use the attribute on the base type. They inject the converters upon serializer creation so that they do not affect the subtypes. And maybe it's important to only check the base type in CanConvert, too, depending on the use case.