1

Using json.net this test fails by default:

JsonConvert.DeserializeObject(
    JsonConvert.SerializeObject(new object()), 
    typeof(object)
).ShouldBeOfType<object>(); // actual type is JObject

Is there a way to change this behavior, so it deserializes to the actual requested type?

1 Answer 1

3

You have a degenerate test case there. If you instruct Json.Net to deserialize into type object, you are telling it that the JSON could represent any possible object. So it will choose to use a JObject in that case, since you were not specific and a JObject can handle any JSON object. It is not expecting that you want to deserialize into a literal empty object instance, because that is not a very useful thing to do. If the JSON contained any data at all, you would not be able to access that data after the deserialization: object has no properties!

You can fix your test by creating an empty class Foo and using that in place of object:

JsonConvert.DeserializeObject(
    JsonConvert.SerializeObject(new Foo()), typeof(Foo)
).ShouldBeOfType<Foo>();

If you really do need to force Json.Net to deserialize into an empty object instance whenever object is specified as the type, you can do it using a custom JsonConverter like this:

public class EmptyObjectConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(object);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);  // consume the JSON object from the reader 
        return token.Type == JTokenType.Null ? null : new object();
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Then pass an instance of the converter to JsonConvert.DeserializeObject():

JsonConvert.DeserializeObject(
    JsonConvert.SerializeObject(new object()), 
    typeof(object),
    new EmptyObjectConverter()
).ShouldBeOfType<object>();

Fiddle: https://dotnetfiddle.net/7xZ7tm

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

4 Comments

Thank you for your answer, but deserialising into an empty object is actually what I want to do, as the test case reflects. I can see why this is not usually useful and I understand the chosen behavior, but I would like to be able to change it. I need to have an instance of the same type on both sides and that type can sometimes be object. I can of course wrap it, check the given type and create the object myself if needed, but I just wondered, if there was a "built in" way. I was not able to do it with a custom contract resolver, but I might have overlooked something.
You can do what you want with a custom JsonConverter. I've updated my answer.
You might want to check for reader.TokenType == JsonToken.Null. Currently JObject.Parse("null"); throws an exception rather than returning null.
Ah yes, why didn't I think of that, that's exactly it. Thanks! :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.