1

I'm using Json.NET and setting TypeNameHandling to Object or All. When the deserializer is selecting a converter for an object, I'm finding it passes the declared type of the object to each JsonConverter's CanConvert, rather than the actual type (as described by the object's $type node).

This causes problems if I have different converters for different classes that all implement a common interface, and I use that interface as a property type in a parent object.

In the code sample below, notice that the ConverterClassA is used in the second test case, but it is not used in the first test case.

Does anyone have a workaround for this so that the Converter is chosen based on the actual type of the object being deserialized, rather than the declared type of the object being serialized?

(note that while this code example doesn't show it, the Serialize (writing JSON) does correctly use the actual type of the member, not the declared type. It seems to only be the Deserializer (reading of JSON) that is what I would define as 'broken').

Thanks in advance, -Eric.

interface IMyInterface
{
}

class ClassA : IMyInterface
{
}

class ParentOfInterface
{
    public IMyInterface Child;
}

class ParentOfA
{
    public ClassA Child;
}

class ConverterClassA : JsonConverter
{
    public override bool CanWrite { get { return false; } } // only read
    public override bool CanConvert(Type objectType)
    {
        Debug.WriteLine(String.Format("{0}.CanConvert({1})", this.GetType().Name, objectType.Name));
        return objectType == typeof(ClassA);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        Debug.WriteLine(String.Format("{0}.ReadJson() CONVERTER IS BEING USED!", this.GetType().Name));
        var ret = new ClassA();
        serializer.Converters.Remove(this);
        serializer.Populate(reader, ret);
        serializer.Converters.Add(this);
        return ret;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

class Program
{
    static void Main(string[] args)
    {
        var settings = new JsonSerializerSettings
        {
            Formatting = Formatting.Indented,
            TypeNameHandling = TypeNameHandling.All,
            Converters = new JsonConverter[] { new ConverterClassA() }
        };

        Debug.WriteLine("Testing ParentOfInterface");
        var pi = new ParentOfInterface();
        pi.Child = new ClassA();
        var str = JsonConvert.SerializeObject(pi, settings);
        Debug.WriteLine("Going to Deserialize ParentOfInterface");
        var pi2 = JsonConvert.DeserializeObject<ParentOfInterface>(str, settings); // converter IS NOT used!

        Debug.WriteLine("Testing ParentOfA");
        var pa = new ParentOfA();
        pa.Child = new ClassA();
        var stra = JsonConvert.SerializeObject(pa, settings);
        Debug.WriteLine("Going to Deserialize ParentOfA");
        var pa2 = JsonConvert.DeserializeObject<ParentOfA>(stra, settings); // converter IS used!
    }
}

Debug Output:

Testing ParentOfInterface
ConverterClassA.CanConvert(ParentOfInterface)
ConverterClassA.CanConvert(ClassA)
Going to Deserialize ParentOfInterface
ConverterClassA.CanConvert(ParentOfInterface)
ConverterClassA.CanConvert(IMyInterface) **note, converter is not used! ***
Testing ParentOfA
ConverterClassA.CanConvert(ParentOfA)
ConverterClassA.CanConvert(ClassA)
Going to Deserialize ParentOfA
ConverterClassA.CanConvert(ParentOfA)
ConverterClassA.CanConvert(ClassA)
ConverterClassA.ReadJson() CONVERTER IS BEING USED!
user1757226
  • 193
  • 2
  • 9
  • This is true -- once you use a `JsonConverter` it takes complete control of deserialization including parsing of `"$type"`. For ways to implement handling of `"$type"` inside `ReadJson()` see [How to deserialize json objects into specific subclasses?](https://stackoverflow.com/a/36587265/3744182) or [Using custom JsonConverter and TypeNameHandling in Json.net](https://stackoverflow.com/q/29810004/3744182). – dbc Aug 11 '17 at 19:15

0 Answers0