JamesNK / Newtonsoft.Json

Json.NET is a popular high-performance JSON framework for .NET
https://www.newtonsoft.com/json
MIT License
10.76k stars 3.25k forks source link

Deserialization of derived type works only when "$type" is first attribute in JSON object #2936

Closed mikolaj-milewski closed 7 months ago

mikolaj-milewski commented 7 months ago

Source/destination types

internal class Base
{
    public string Name { get; set; }
}

internal class Derived : Base
{ }

Source/destination JSON

{"Name":"test","$type":"Derived, DeserializationError"}

Expected behavior

I'd like to get instance of Derived class.

Actual behavior

I'm getting instance of Base class.

Steps to reproduce

var settings = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All };

var json1 = "{\"Name\":\"test\",\"$type\":\"Derived, DeserializationError\"}";
var obj1 = JsonConvert.DeserializeObject<Base>(json, settings); // obj1 has Base type

var json2 = "{\"$type\":\"Derived, DeserializationError\",\"Name\":\"test\"}";
var obj2 = JsonConvert.DeserializeObject<Base>(json, settings); // obj2 has Derived type
elgonzo commented 7 months ago

Deserialization of derived type works only when "$type" is first attribute in JSON object

Not a bug, and also an incorrect statement. Newtonsoft.Json also supports scenarios where the "$type" metadata property is not the first property in a Json object.

However, since this pretty much requires the serializer to buffer data (up to the point where it comes across the "$type" property), which is incurring both a perf and memory cost, this behavior needs to be explicitly enabled by setting JsonSerializerSettings.MetadataPropertyHandling to MetadataPropertyHandling.ReadAhead.

mikolaj-milewski commented 7 months ago

Thank you for an explanation!