codecutout/JsonApiSerializer

De-serialization issue when attribute is an array of objects

Opened this issue · 1 comments

Hi, given the following contracts

   public class ResourceA
    {
      public string Id { get; set; }
      public string Type { get; set; } = "A";
      public ResourceB ResourceB { get; set; }
    }

    public class ResourceB
    {
      public string Id { get; set; }
      public string Type { get; set; } = "B";
      public ResourceC[] ResourceCs { get; set; }
    }

    public class ResourceC
    {
      public string Id { get; set; }
      public string Type { get; set; } = "C";
      public DateTimeOffset DateTimeOffset { get; set; }
    }

and the following jsonapi instance

{
  "data": {
    "id": "8a45fc9f-8d08-49d1-9f21-43fe7d27b47f",
    "type": "A",
    "relationships": {
      "resourceB": {
        "data": {
          "id": "20fa444b-38d7-481f-ac00-ef86b92fc8c0",
          "type": "B"
        }
      }
    }
  },
  "included": [
    {
      "id": "20fa444b-38d7-481f-ac00-ef86b92fc8c0",
      "type": "B",
      "attributes": {
        "resourceCs": {
          "data": []
        }
      }
    }
  ]
}

what we get with v1.7.4 is an instance of ResourceA with a property of ResourceB with an array containing a default instance of ResourceC, with Id=null, and DateTimeOffset=default(DateTimeOffset) (instead of an empty array).
With version 1.3.1, the array was empty as expected.
I noticed that renaming attributes to relationships does work but in our case it comes from an external service..

In any case, is this a bug? Thanks

ResourceCs is in the attributes so its treated as regular JSON serialization, it does not do any special handling of data property, its expecting your ResourceC object to have a data property to deserialize into. It is the equivalent of JsonConvert.DeserializeObject<ResourceC>(@"{""Data"":[]}"), which will return a default ResourceC (Id=null, and DateTimeoOffset=defalt(DateTimeOffset))

The model that more accurately fits your JSON is

public class ResourceA
{
    public string Id { get; set; }
    public string Type { get; set; } = "A";
    public ResourceB ResourceB { get; set; }
}

public class ResourceB
{
    public string Id { get; set; }
    public string Type { get; set; } = "B";
    public ResourceCData ResourceCs { get; set; }
}

public class ResourceCData
{
    public ResourceC[] Data { get; set; }
}

public class ResourceC
{
    public string Id { get; set; }
    public string Type { get; set; } = "C";
    public DateTimeOffset DateTimeOffset { get; set; }
}

ResourceC is not real Resource object, it is just an attribute that happens to have similar fields to a resource object.