I am trying to deserialize a complex nested json to my object.
The only thing is that in my object I use abstract types, so it must have some logic to use the correct derived class.
The types are saved in enums.
To explain it I will keep it fairly simple and do we only nest once, but for my purpose it is more nested with objects and types.
The json
{
"screen":{
"type":"Component",
"footer":{
"type":"Bar"
},
"header":{
"type":"Top"
}
}
}
The classes
public abstract class Screen
{
public abstract ScreenType Type { get; }
}
public enum ScreenType
{
Component,
b,
c,
d,
e
}
public sealed class ComponentScreen : Screen
{
public override ScreenType Type => ScreenType.Component;
public Header? Header { get; init; }
public Footer? Footer { get; init; }
public bool? ShowStuff {get; init; }
}
public abstract class Header : ITyped<HeaderType>
{
public abstract HeaderType Type { get; }
}
public enum HeaderType
{
Top,
b,
c,
d
}
public sealed class TopScreenHeader : Header
{
public override HeaderType Type => HeaderType.Top;
public string MyStuff { get; }
}
It isn’t possible to just change all the abstract types, or writing converters, since there are multiple abstract types with times X derived objects.
The JSON is also not consistent.
My current code using newtonsoft
var screen = JsonConvert.DeserializeObject<Screen>(jsonString, new JsonSerializerSettings {
TypeNameHandling = TypeNameHandling.Objects,
ContractResolver = new CamelCasePropertyNamesContractResolver()
}
Which doesn’t work and gives errors:
Could not create an instance of type Screens.Screen. Type is an interace or abstract class and cannot be instantiated. Path 'screen', line 1, position 10.
2
Answers
Not a direct answer but if you are considering migrating to .NET 7+ and
System.Text.Json
you can useSystem.Text.Json
‘s ability to handle type hierarchies:Note that your json does not represent screen but some screen holder type so:
And usage (for
footer
I have used simple class):As for Newtonsoft Json.NET there are following options:
SerializationBinder
.Also note that using
TypeNameHandling
with other option other thanNone
and without properSerializationBinder
can lead to application vulnerabilities.you have a bug in you json convert code , you need add a root class. Also you need to include a class name in your json string to point what class to use to deserialize. To do it easier to create a base class for all your abstract classes
it will create a json string of this kind
you can use this converter to convert from base class to concrete one