as a partial problem of this question JSON.NET CustomCreationConverter with nested objects I tried to call a custom constructor during deserialization. My simplified class hierarchy is as follows:
public abstract class BusinessObjectBase
{
internal BusinessObjectBase(SerializationContext context)
: base(context)
{
}
}
public abstract class EditableObjectBase : BusinessObjectBase
{
protected EditableObjectBase(SerializationContext context)
: base(context)
{
}
}
public class EditableObjectCollection<TObject> : BusinessObjectBase, ICollection<TObject>, IList, INotifyCollectionChanged where TObject : BusinessObjectBase
{
protected EditableObjectCollection(SerializationContext context)
: base(context)
{
}
}
I know the object hierarchy to a certain level, but users are allowed / forced to derive their own classes. My idea was to write a custom creation converter. The problem I'm fighting with is that a property in a serialized object can be declared as BusinessObjectBase which is abstract, but the real object will be a more derived class and might be a collection or not. A CustomCreationConverter only gets this abstract type passed to the Create method and of course can't create the correct type from this information.
Inspired from this How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects I implemented a converter as follows:
internal class BusinessObjectCreationConverter : JsonConverter
{
public override bool CanWrite
{
get
{
return false;
}
}
public override bool CanConvert(Type objectType)
{
return typeof(BusinessObjectBase).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object result = null;
if (reader.TokenType != JsonToken.Null)
{
JObject jsonObject = JObject.Load(reader);
result = this.Create(objectType, jsonObject);
Verification.Assert<NullReferenceException>(result != null, "No Business Object created.");
serializer.Populate(jsonObject.CreateReader(), result);
}
return result;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
}
public BusinessObjectBase Create(Type objectType, JObject jsonObject)
{
JToken token = jsonObject.SelectToken("$type");
var typeString = token.Value<string>();
Type type = Type.GetType(typeString);
var businessObject = type.CreateUsingDesrializationConstructor<BusinessObjectBase>();
businessObject.Initialize(true);
return businessObject;
}
}
My class to test serialization looks like this:
public class AnyPocoContainingBusinessObject
{
public BusinessObjectBase BusinessObject { get; set; }
}
public class TestEditableObject : EditableObjectBase
{
internal TestEditableObject(SerializationContext context)
: base(context)
{
}
}
If I initialize my class my class with an collection
var collection = new EditableObjectCollection<TestEditableObject>(null);
var poco = new AnyPocoContainingBusinessObject { BusinessObject = collection };
and configure the serializer this way:
public NewtonsoftJsonSerializer()
: this(new JsonSerializer
{
TypeNameHandling = TypeNameHandling.Auto,
ObjectCreationHandling = ObjectCreationHandling.Replace,
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
DefaultValueHandling = DefaultValueHandling.Ignore,
ContractResolver = new KsJsonContractResolver()
})
{
this.serializer.Converters.Add(new ReadOnlyObjectCollectionConverter());
this.serializer.Converters.Add(new BusinessObjectCreationConverter());
this.serializer.TraceWriter = new ConsoleTraceWriter();
}
I get an exception: Cannot populate JSON object onto type 'KS.Interfaces.Core.Entities.EditableObjectCollection`1[KS.Interfaces.Core.Entities.Tests.Unit.EditableObjectCollectionTests+TestEditableObject]'. Path '$type', line 1, position 47.
in this code line of my converter:
serializer.Populate(jsonObject.CreateReader(), result);
Can any body tell me what might be the reason? I'm pretty sure that I created the correct type and with a EditableObjectBase derived object everything is fine. Only collections doesn't seem to work.
Any hints are highly appreciated, thank in advance Carsten