j_maly j_maly - 4 days ago 4
C# Question

Json.NET custom serialization with JsonConverter - how to get the "default" behavior

I have a JsonConverter for my class DataType.
I would like to do some special handling when plain string used in Json as the value of a property of type DataType. In the case where the value is a "full" object, I would like to do the "normal" deserialization.

Here is my attempt

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.Value != null && reader.ValueType == typeof (string))
{
return someSpecialDataTypeInstance;
}
else if (reader.TokenType == JsonToken.StartObject)
{
DataType dataType = serializer.Deserialize<DataType>(reader);
return dataType;
}
else
{
throw new JsonSerializationException();
}
}


But this doesn't work, because this line:
DataType dataType = serializer.Deserialize(reader);
causes infinite recursion.

Could this be done somehow easily? (without the need to manually go property-by-property)

dbc dbc
Answer

One easy way to do it is to allocate an instance of your class then use JsonSerializer.Populate(JsonReader, Object). This is the way it is done in the standard CustomCreationConverter<T>:

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.Value != null && reader.ValueType == typeof(string))
        {
            return someSpecialDataTypeInstance;
        }
        else if (reader.TokenType == JsonToken.StartObject)
        {
            existingValue = existingValue ?? serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
            serializer.Populate(reader, existingValue);
            return existingValue;
        }
        else if (reader.TokenType == JsonToken.Null)
        {
            return null;
        }
        else
        {
            throw new JsonSerializationException();
        }
    }

Note that this does not handle situations when TypeNameHandling has been enabled and a "$type" property is present specifying a polymorphic subtype. In that case you'll need to do some of the tricks from the updated JsonDerivedTypeConverer<T> in JsonConverter with Interface.

Sample fiddle.

Comments