Home > Software engineering >  How to check the value type in a JSON and decide whether to deserialize?
How to check the value type in a JSON and decide whether to deserialize?

Time:12-08

Given the following structure:

"meta": {
  "pagination": {
    "total": 378,
    "count": 50,
    "per_page": 50,
    "current_page": 2,
    "total_pages": 8,
    "links": {
        "previous": "https://myapi.com.br/api/clients?page=1",
        "next": "https://myapi.com.br/api/clients?page=3"
    }
}

Sometimes the value of the property "links" is returned as an empty array.

"meta": {
  "pagination": {
    "total": 14,
    "count": 14,
    "per_page": 50,
    "current_page": 1,
    "total_pages": 1,
    "links": []
  }
}

So I created a type inherited from JsonConverter to set in my class property.
This is where I don't know how to proceed.

public class LinksJsonConverter : JsonConverter
{
    public override bool CanWrite => false;

    public override bool CanConvert(Type objectType)
        => objectType == typeof(Links);

    public override object ReadJson(JsonReader reader, Type objectType, 
        object existingValue, JsonSerializer serializer)
    {
        var links = new Links();
        if (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.EndArray)
            return links; // try return null
        JObject jo = JObject.Load(reader);
        links.Previous = jo["Previous"]?.ToString() ?? string.Empty;
        links.Next = jo["Next"]?.ToString();?? string.Empty;          
        return links;
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        => ...
}

The classes:

public class Links
{
    public string Previous { get; set; }
    public string Next { get; set; }
}

public class Pagination
{
    public int Total { get; set; }
    public int Count { get; set; }

    [JsonProperty("per_page")]
    public int PerPage { get; set; }

    [JsonProperty("current_page")]
    public int CurrentPage { get; set; }

    [JsonProperty("total_pages")]
    public int TotalPages { get; set; }
    
    [JsonConverter(typeof(LinksJsonConverter))]
    public Links Links { get; set; }
}

The error when I try to convert from empty "links" property. When the value is an empty array:

Message: 
Test method IntegrationDownloaderServiceTests.ShouldProcessResultNfe threw exception: 
Newtonsoft.Json.JsonSerializationException: Unexpected token when deserializing object: 
EndArray. Path 'meta.pagination.links', line 123, position 17.

How to solve this case?

CodePudding user response:

in first step deserialize link as object :

public class Pagination
{
    public int total { get; set; }
    public int count { get; set; }
    public int per_page { get; set; }
    public int current_page { get; set; }
    public int total_pages { get; set; }
    public object links { get; set; }
}

public class Meta
{
    public Pagination pagination { get; set; }
}

public class Root
{
    public Meta meta { get; set; }
}

then check links type: (this)

public static class TypeExtensions
{
    public static bool IsArrayOf<T>(this Type type)
    {
         return type == typeof (T[]);
    }
} 

and decide convert object to array or not.

CodePudding user response:

I probably wasn't clear enough about my question.
I want to ignore the array value (at least for now) until the day it makes sense.
In the documentation of this API I didn't find references about it.
I will try to contact the developer.

This way it worked:

public override object ReadJson(JsonReader reader, Type objectType, 
    object existingValue, JsonSerializer serializer)
{
    if (reader.TokenType == JsonToken.StartObject)
    {
        JObject jo = JObject.Load(reader);
        var links = new Links
        {
            Previous = jo["previous"]?.Value<string>() ?? string.Empty,
            Next = jo["next"]?.Value<string>() ?? string.Empty
        };
        return links;
    }
    else if (reader.TokenType == JsonToken.StartArray)
    {
        reader.Skip();
    }

    return null;
}
  • Related