-2

I am trying to convert the following JSON into C# classes using Json.Net. However, I am getting an exception. Here is the JSON:

Newtonsoft.Json.JsonSerializationException: 'Could not create an instance of type Viewer.ShapeDto. Type is an interface or abstract class and cannot be instantiated. Path '[0].type', line 3, position 13.'

Here is the JSON:

[  
   {  
      "type":"line",
      "a":"-1,5; 3,4",
      "b":"2,2; 5,7",
      "color":"127; 255; 255; 255",
      "lineType":"solid"
   },
   {  
      "type":"circle",
      "center":"0; 0",
      "radius":15.0,
      "filled":false,
      "color":"127; 255; 0; 0",
      "lineType":"dot"
   }
]

And here are the C# classes I am using:

public abstract class ShapeDto
{
    [JsonProperty(PropertyName = "type")]
    public abstract string Type { get; }

    [JsonProperty(PropertyName = "color")]
    public string Color { get; set; }

    [JsonProperty(PropertyName = "lineType")]
    public string LineType { get; set; }
}

public sealed class LineDto : ShapeDto
{
    public override string Type => "line";

    [JsonProperty(PropertyName = "a")]
    public string A { get; set; }

    [JsonProperty(PropertyName = "b")]
    public string B { get; set; }
}

public sealed class CircleDto : ShapeDto
{
    public override string Type => "circle";

    [JsonProperty(PropertyName = "center")]
    public string C { get; set; }

    [JsonProperty(PropertyName = "radius")]
    public double R { get; set; }

    [JsonProperty(PropertyName = "filled")]
    public bool Filled { get; set; }
}

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

        var shapes = JsonConvert.DeserializeObject<IList<ShapeDto>>(json, settings);
Vahid
  • 5,144
  • 13
  • 70
  • 146
  • It is telling you what the problem is: `Type is an interface or abstract class and cannot be instantiated. ` – Ňɏssa Pøngjǣrdenlarp Jul 27 '19 at 21:35
  • But isn't it smart enough to find out that I want to instantiate the derived classes? There should be a configuration or settings somewhere? – Vahid Jul 27 '19 at 21:39
  • Better duplicates would include [Deserializing polymorphic json classes without type information using json.net](https://stackoverflow.com/q/19307752/3744182), [Json.Net Serialization of Type with Polymorphic Child Object](https://stackoverflow.com/q/29528648/3744182) or [How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects?](https://stackoverflow.com/q/8030538/3744182). – dbc Jul 28 '19 at 01:09

1 Answers1

0

The exception is pretty clear. You cannot deserialize into an abstract class (or an interface).

That's because Json.Net is going to create a new instance of the type you requested (ShapeDto) and fill its properties. Since the type you requested is abstract, it cannot be constructed.

And if you try to make it non-abstract, it won't have the specific properties of the Circle and Line classes.

This means you cannot deserialize generically like you're trying to do. You have to know the type beforehand if you are going to deserialize to a type.

Edu
  • 2,354
  • 5
  • 32
  • 36
  • But Edu my JSON file consists of several different objects. They all inherit from ShapeDto. I am confused. – Vahid Jul 27 '19 at 21:43
  • Json.Net only knows what you provide to it, in this case through the generic type you sent when calling the method to deserialize. It will only know that ShapeDto exists, it doesn't know that child classes exist for it. And how would it be able to guess if more than one class is valid for deserialization? – Edu Jul 27 '19 at 21:50
  • If you have control over the serialization, an easy solution is to create a new class with 2 properties, the Json and the type name, and serialize that to Json and deliver it. Then on deserialization, you can deserialize to that new type, use the type name to find the type and use it for the final deserialization. – Edu Jul 27 '19 at 21:51
  • Unfortunately, I do not have any control over that. I changed my classes so, the base class is not abstract anymore. Now when I deserialize the final list of objects only contains ShapeDto! LineDto and CircleDto are lost. – Vahid Jul 27 '19 at 21:53
  • 1
    That's what I've said. You have to deserialize to correct type if you want to use the deserialization to a specific type. Since you have no control over the serialization, then you'll have to build a way to know which type a Json has for all elements of your list. In your case, parse the Json and check for a property that only appears in a certain type. – Edu Jul 27 '19 at 21:58
  • *You have to know the type beforehand if you are going to deserialize to a type.* -- not necessarily. You can create a `JsonConverter` that pre-loads the JSON and checks the `"type"` string to determine a concrete type. See: [Deserializing polymorphic json classes without type information using json.net](https://stackoverflow.com/q/19307752/3744182) or [Json.Net Serialization of Type with Polymorphic Child Object](https://stackoverflow.com/q/29528648/3744182). – dbc Jul 28 '19 at 01:18
  • @dbc What JsonConverter works for and does is the proof of what I said. You cannot deserialize to a type if you don't know which type holds the Json. That's why that concept exists in the first place. In fact, in the first link you provided, the JsonConverter is implemented to do what I've said in the previous comment, which is to parse the Json and try to identify the type through any unique properties. – Edu Jul 28 '19 at 09:05