17

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)

1

1 Answer 1

16

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();
    }
}

Limitations:

Sample fiddle.

Sign up to request clarification or add additional context in comments.

8 Comments

The DefaultConvert() call throws NRE at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue). I replaced it with direct constructor call.... apart from that, thanks for your answer!
@j_maly - i'm having the same issue, but I can't figure out what the solution is based on your comment. Can you post the modifications you made to this answer?
@dbc - Thank you for posting that fiddle. It seems you are still calling DefaultCreator(). Like j_maly, I'm getting a NullReferenceException on DefaultCreator(). j_maly said "I replaced it with direct constructor call", but I couldn't interpret what he/she meant by that. I was looking for the replacement/fix to solve the NullReferenceException issue.
@SFun28 - does your type have a public parameterless constructor? If not that might be the problem. If your type only has a single constructor, and that constructor is parameterized, then DefaultCreator() won't work. Instead you'll have to construct your type manually by calling new MyType(arg1, arg2, ... ).
@dbc - my type does not have a public parameterless constructor. I do have a customized contract resolver. I also know that if my JsonConverter return false for CanConvert, that json.net is able to deserialize the type using the customized contract resolver. Does that open up any options?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.