0

I need to deserialize this json using NewtonsoftJson:

{
    "players": [
    {
        "player_id": "331574",
        "team_id": "95",
    },
    {  
        "player_id": "331575",
        "team_id": "95",
    }],
    "coach": 
     {
        "id": "249197",
        "first_name": "Guillermo",
    }
}

so I have this class:

 public class Squad
    {
        public List<Player> players { get; set; }
        public Coach coach { get; set; }

        public class Coach
        {
            public int id { get; set; }
            public string first_name { get; set; }
        }

        public class Player
        {
            public int player_id { get; set; }
            public int team_id { get; set; }
        }
    }

for deserialize I use:

return JsonConvert.DeserializeObject<Squad>(content);

now sometimes I get the coach null:

 {
    "players": [
    {
        "player_id": "331574",
        "team_id": "95",
    },
    {  
        "player_id": "331575",
        "team_id": "95",
    }],
    "coach": []
  }

So I implemented the converter suggested in this question: How to handle both a single item and an array for the same property using JSON.net

in particular, the only edit I did was:

[JsonConverter(typeof(SingleOrArrayConverter<object>))]
 public Coach coach { get; set; }

but I get this error when deserialize:

Can not cast objects of type 'System.Collections.Generic.List`1 [System.Object]' on the 'Coach' type.

Charanoglu
  • 1,229
  • 2
  • 11
  • 30
  • 2
    The property needs to be a collection/list: `public List coach { get; set; }` – maccettura Jun 27 '18 at 15:08
  • That looks like an array, not null. – itsme86 Jun 27 '18 at 15:09
  • @maccettura I changed the api to return null instead of [] now I get: `'Error setting value to 'coach' on 'SWP.Models.Team+Squad'.' ` – Charanoglu Jun 27 '18 at 15:13
  • @Charanoglu why would you do that? Keep everything the way it was, just change the `coach` property to a `List` – maccettura Jun 27 '18 at 15:14
  • @maccettura That won't work for the JSON in the first example where coach isn't an array. – itsme86 Jun 27 '18 at 15:15
  • @itsme86 it will if OP actually implemented the change they said they did in their question (the custom Converter) – maccettura Jun 27 '18 at 15:15
  • Can a team have multiple coaches? If so, just always make it an array. If a team can't have multiple coaches, just return null for the coach if there isn't one. – itsme86 Jun 27 '18 at 15:17
  • @maccettura coach is a single record not an array that's why I change the empty result – Charanoglu Jun 27 '18 at 15:35
  • @Charanoglu your JSON: `"coach": []` _very clearly_ tells us that coach is an empty array. If Coach will never be an array and will only ever be one then you need to change the context of your question and there would be no need to implement that attribute – maccettura Jun 27 '18 at 15:37

1 Answers1

1

You just need to change Coach to be List<Coach>

class Program
{
    static void Main(String[] args)
    {
        var str1 = "{\"players\":[{\"player_id\":\"331574\",\"team_id\":\"95\",},{\"player_id\":\"331575\",\"team_id\":\"95\",}],\"coach\":{\"id\":\"249197\",\"first_name\":\"Guillermo\",}}";
        var obj1 = JsonConvert.DeserializeObject<Squad>(str1);

        var str2 = "{\"players\":[{\"player_id\":\"331574\",\"team_id\":\"95\",},{\"player_id\":\"331575\",\"team_id\":\"95\",}],\"coach\":[]}";
        var obj2 = JsonConvert.DeserializeObject<Squad>(str2);
    }
}

public class Squad
{
    public List<Player> players { get; set; }

    [JsonProperty("coach")]
    [JsonConverter(typeof(SingleOrArrayConverter<Coach>))]
    public List<Coach> coach { get; set; }
    public class Coach
    {
        public int id { get; set; }
        public string first_name { get; set; }
    }

    public class Player
    {
        public int player_id { get; set; }
        public int team_id { get; set; }
    }
}

class SingleOrArrayConverter<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
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}
Ray Krungkaew
  • 6,652
  • 1
  • 17
  • 28