Skip to content

Instantly share code, notes, and snippets.

@StephenCleary
Created September 6, 2017 01:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save StephenCleary/f10245ab46ca269fe62e64f401ed4c9e to your computer and use it in GitHub Desktop.
Save StephenCleary/f10245ab46ca269fe62e64f401ed4c9e to your computer and use it in GitHub Desktop.
A JsonConverter that determines the type of the deserialized object by its JSON representation. Combination of several approaches including CustomCreatorConverter and https://stackoverflow.com/questions/22537233/json-net-how-to-deserialize-interface-property-based-on-parent-holder-object/22539730#22539730
/// <summary>
/// Creates a custom object based on the json values.
/// </summary>
/// <typeparam name="T">The object type to convert.</typeparam>
public abstract class JsonCreationConverter<T> : JsonConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var jobject = JObject.Load(reader);
var type = GetType(jobject, objectType, existingValue);
if (type == null)
throw new JsonSerializationException("Could not determine object type.");
return jobject.ToObject(type, serializer);
}
/// <summary>
/// Determines the type of object being deserialized.
/// </summary>
/// <param name="json">The JSON object.</param>
/// <param name="objectType">Type that JSON.NET thinks the object should be. This parameter is usually ignored.</param>
/// <param name="existingValue">The existing value of the object being read. This parameter is usually ignored.</param>
public abstract Type GetType(JObject json, Type objectType, object existingValue);
public override bool CanConvert(Type objectType) => typeof(T).IsAssignableFrom(objectType);
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotSupportedException("JsonCreationConverter should only be used while deserializing.");
}
@StephenCleary
Copy link
Author

Untested.

When JSON.NET vNext is released, this should change its base class to JsonConverter<T> and pass T existingValue, bool hasExistingValue to GetType.

@PatryxCShark
Copy link

typeof(T).IsAssignableFrom(objectType) - I get objectType as my base class form jsonString event if in json string there is conrete class.
For example:
abstract class ClassBase

class ClassA : ClassBase

and I have in json string information about type: ClassA but while deserializon CanConvert(Type objectType) the objectType name is ClassBase and then typeof(T).IsAssignableFrom(objectType) is alsways false.

Does sb know why? How to get in objectType the conrete class (here ClassA?)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment