anon
anon

Reputation:

Could not create an instance of type X. Type is an interface or abstract class and cannot be instantiated

Using version 7.0.1 Beta3, I'm trying to serialize/deserialize a complex POCO with properties that are arrays of abstract classes. These arrays could contain instance of classes that are derived from abstract ones.

At serialization, everything seems OK. The Json fragment below shows that the type information is set correctly.

The Json fragment:

 "Items": 
 [
     {
         "$type": "IVXB_TS, ...",
         "inclusive": true,
         "value": "20091231"
     }
 ]

But a deserialization it fails with the following error:

Could not create an instance of type QTY. Type is an interface or abstract class and cannot be instantiated.

The class hierarchy is the following :

[System.Xml.Serialization.XmlIncludeAttribute(typeof(IVXB_TS))]
public abstract partial class ANY : object, System.ComponentModel.INotifyPropertyChanged
{
}

[System.Xml.Serialization.XmlIncludeAttribute(typeof(IVXB_TS))]
public abstract partial class QTY : ANY
{
}

[System.Xml.Serialization.XmlIncludeAttribute(typeof(IVXB_TS))]
public partial class TS : QTY
{
}

public partial class IVXB_TS : TS
{
}

The Items property :

[System.Xml.Serialization.XmlElementAttribute("high", typeof(IVXB_TS))]
[System.Xml.Serialization.XmlElementAttribute("low", typeof(IVXB_TS))]
public QTY[] Items

The type information in the Json fragment seems to not be used. Is this a deserialization configuration issue?

Upvotes: 54

Views: 72949

Answers (3)

user15719632
user15719632

Reputation:

If you specify Null Value Handling you won't get this error.

    new JsonSerializerSettings
    {
        NullValueHandling = NullValueHandling.Ignore
    }));

You could also set the [JsonIgnore] flag

Image of the JsonIgnore flag

Both of these options worked fine for the use case that brought me here.

Type name handling wasn't necessary.

Upvotes: -2

Amir Mahdi Nassiri
Amir Mahdi Nassiri

Reputation: 1330

In my case, setting the TypeNameHandling to Auto didn't fix the problem, but setting it to All fixed the issue. As the TypeNameHandling = TypeNameHandling.All seemed a bit overkill to me, I chose Auto again, but this time, I passed the type of my root object to the JsonConvert.SerializeObject function as well:

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

var json = JsonConvert.SerializeObject(obj, typeof(ObjType), settings);

var deserializedObj = JsonConvert.DeserializeObject<ObjType>(json, settings);

Upvotes: 19

anon
anon

Reputation:

The solution to this problem is to configure the deserializer to use the type information in the json. It is not used by default.

Serialization is done this way:

Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
serializer.Converters.Add(new Newtonsoft.Json.Converters.JavaScriptDateTimeConverter());
serializer.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
serializer.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto;
serializer.Formatting = Newtonsoft.Json.Formatting.Indented;

using (StreamWriter sw = new StreamWriter(fileName))
using (Newtonsoft.Json.JsonWriter writer = new Newtonsoft.Json.JsonTextWriter(sw))
{
    serializer.Serialize(writer, obj, typeof(MyDocumentType));
}

At deserialization, the settings for TypeNameHandling must be set:

MyDocumentType  obj = Newtonsoft.Json.JsonConvert.DeserializeObject<MyDocumentType>(File.ReadAllText(fileName), new Newtonsoft.Json.JsonSerializerSettings 
{ 
    TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto,
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
});

Upvotes: 78

Related Questions