codecutout / JsonApiSerializer

JsonApiSerializer supports configurationless serializing and deserializing objects into the json:api format (http://jsonapi.org).
MIT License
113 stars 46 forks source link

Updating JsonApiSerializer from 1.3.1 to 1.74 Custom converters #139

Closed CyberNomadDev closed 2 years ago

CyberNomadDev commented 2 years ago

I am trying to upgrade a project from 1.3.1 to 1.74 that uses a customer converter. Everything works OK in 1.3.1 but fails with 1.74 with the error below. Am I adding the custom converter to the MyJsonApiSerializerSettings in the correct way?

JsonSerializationException: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.IEnumerable`1[PUBGChampionApi.PubgPlayer]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'data', line 1, position 8.

I've added a MyJsonApiSerializerSettings class and into the method to try and get it to call the custom converter

 public  class MyJsonApiSerializerSettings : JsonSerializerSettings
    {
        public MyJsonApiSerializerSettings(JsonConverter resourceObjectConverter)
        {            
            base.Converters.Add(new RelationshipIdConverter());
        }

        public MyJsonApiSerializerSettings()
            : this(new ResourceObjectConverter())
        {
        }
    }
var settings = new MyJsonApiSerializerSettings()
var converted = JsonConvert.DeserializeObject<IEnumerable<PubgPlayer>>(collectionJson, settings);

I think it's similar to this question. [JsonConverter] seems to be ignored as of 1.6.0

This is the converter class

public class RelationshipIdConverter : JsonConverter
{
      public override bool CanConvert(Type objectType) => false;
      public override bool CanWrite => false;

      public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
      {
            //if the reader is not reading a relationship object just deserialize as normal.
            //This allows us to serialize and deserialize multiple times after converting from the Json-API format
            if (reader.TokenType != JsonToken.StartObject)
                return serializer.Deserialize(reader, objectType);

            JToken jt = JToken.Load(reader);

            var dataToken = jt.SelectToken("data");

            if (objectType == typeof(string))
                return dataToken["id"].ToString();

            return dataToken.Select(x => (string)x["id"]).ToList();
      }

      public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { }
}

The class I'm trying to deserialize into

public class PubgPlayer : PubgShardedEntity
{      
    [JsonProperty("Name")]
    public string Name { get; set; }

    [JsonProperty]
    public DateTime CreatedAt { get; set; }

    [JsonProperty]
    public string PatchVersion { get; set; }

    [JsonProperty]
    public string TitleId { get; set; }

    [JsonProperty("matches")]        
    [JsonConverter(typeof(RelationshipIdConverter))]
    public IEnumerable<string> MatchIds { get; set; }
}

Json from API

{
   "data":[
      {
         "type":"player",
         "id":"account.f96f1d482a5d4a21a4135f598f5a5c6a",
         "attributes":{
            "name":"Nomad_o7",
            "stats":null,
            "titleId":"pubg",
            "shardId":"steam",
            "patchVersion":""
         },
         "relationships":{
            "assets":{
               "data":[

               ]
            },
            "matches":{
               "data":[
                  {
                     "type":"match",
                     "id":"e14ca749-3c19-49dd-9486-03de90669fa3"
                  },
                  {
                     "type":"match",
                     "id":"73dbca3e-eeee-44eb-9c43-3f71df0e02ae"
                  },
                  {
                     "type":"match",
                     "id":"e9f80ed0-1e78-4500-950f-174028fb73cc"
                  }
               ]
            }
         },
         "links":{
            "self":"https://api.pubg.com/shards/steam/players/account.f96f1d482a5d4a21a4135f598f5a5c6a",
            "schema":""
         }
      },
      {
         "type":"player",
         "id":"account.82bad0072f31455d8d9f8d834da2f2f3",
         "attributes":{
            "name":"TGLTN",
            "stats":null,
            "titleId":"pubg",
            "shardId":"steam",
            "patchVersion":""
         },
         "relationships":{
            "assets":{
               "data":[

               ]
            },
            "matches":{
               "data":[
                  {
                     "type":"match",
                     "id":"4a6f064e-c292-4e9b-a3a6-bbaed891ce27"
                  },
                  {
                     "type":"match",
                     "id":"efd9434c-4116-4b56-815d-e30903b37c23"
                  },
                  {
                     "type":"match",
                     "id":"c1e56bff-db4c-470b-bb44-3c2068e33245"
                  },
                  {
                     "type":"match",
                     "id":"44d27efc-3cc6-4935-8bbe-702e4da44744"
                  },
                  {
                     "type":"match",
                     "id":"be3ebed3-9183-47f1-b4b0-40a2229dd5ff"
                  }                 
               ]
            }
         },
         "links":{
            "self":"https://api.pubg.com/shards/steam/players/account.82bad0072f31455d8d9f8d834da2f2f3",
            "schema":""
         }
      }
   ],
   "links":{
      "self":"https://api.pubg.com/shards/steam/players?filter[playerNames]=Nomad_o7,TGLTN"
   },
   "meta":{

   }
}