1

I query an API that has a strange serialization pattern. Some properties may either be null (not existing) or an array of objects (default) or even just an object. It depends on how many items are in the list.

{
   persons: null
}

or

{
   persons: { name: "lastname1, firstname1" }
}

or

{
    persons: [{ name: "lastname1, firstname1" }, { name: "lastname2, firstname2" }]
}

Now I want to deserialize this using json.net. But I don't know how to define my model. When I define persons property as List<Person> case 1 and 3 deserialize fine, but case 2 fails; when I define it as a Person, case 1 and 2 deserialize fine. The best would be, when I could define it as a list of persons and write something that instructs json.net to deserialize it correctly. Now json.net has some concepts to intercept serialization and deserialization. What's the best approach to solve this?

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
Martin H.
  • 1,086
  • 1
  • 17
  • 28

2 Answers2

3

I think, there is no option except implementing custom converter;

class CollectionConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(List<T>));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        if (token.Type == JTokenType.Array)
        {
            return token.ToObject<List<T>>();
        }
        return new List<T> { token.ToObject<T>() };
    }

    public override bool CanWrite => false;

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException("There is no writing implemantation");
    }
}

public class PersonList
{
    [JsonConverter(typeof(CollectionConverter<Person>))]
    public List<Person> Persons { get; set; }
}

Deserialize object as collection;

var str = "{ persons: { name: \"lastname1, firstname1\" } }";
var obj = JsonConvert.DeserializeObject<PersonList>(str);

Deserialize collection;

var str = "{ persons: [{ name: \"lastname1, firstname1\" },{ name: \"lastname1, firstname1\" }] }";
var obj = JsonConvert.DeserializeObject<PersonList>(str);
lucky
  • 12,734
  • 4
  • 24
  • 46
  • Thanks for the solution. It was exactly what I was searching for. Though, Brian is right - it is a duplicate of an existing question which pointed out the same solution. – Martin H. Dec 20 '17 at 15:42
0

You can initially check if persons is null ( == null).

Then if you are using json.net,
You can check if persons is an array by using

if(personsJsonParsed is JArray)

If it isn't a JArray then just assume it is an object.

Ya Wang
  • 1,758
  • 1
  • 19
  • 41