Search code examples
c#json.netodoo

How to deserialize a JSON response, where null keyword is replaced with false?


I have the following response from Odoo API, which I would like to deserialize to a C# POCO using Newtonsoft.Json:

{
    "jsonrpc": "2.0",
    "id": 88252859,
    "result": [
        {
            "id": 61,
            "campaign_id": false,
            "source_id": false,
            "medium_id": false,
            "activity_ids": [],
            "activity_state": false,
            "activity_user_id": false,
            "activity_type_id": false,
            "activity_type_icon": false,
            "activity_date_deadline": false,
            "my_activity_date_deadline": false,
            "activity_summary": false,
            "activity_exception_decoration": false,
            "activity_exception_icon": false,
            "activity_calendar_event_id": false,
            (...)
        }
    ]
}

The problem is, Odoo API replaces null with false in the response. For example: property my_activity_date_deadline is of type DateTime?, but Odoo returns it as false. This applies to any nullable type.

How should I approach this? A custom JsonConverter class? Or maybe I should catch and silence exceptions caused by type mismatch, so that the default value is used when property cannot be deserialized?

I found a potential solution on GitHub, in OdooModelConverter using method ConverOdooPropertyToDotNet:

It feels hacky, but I don’t know how to write a more elegant solution.


Solution

  • With this simple converter:

    public class FalseToNullConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType) => true;
    
        public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
            => reader.TokenType != JsonToken.Boolean || reader.Value is not false 
                ? serializer.Deserialize(reader, objectType)
                : null;
    
        public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
            => throw new NotImplementedException();
    }
    

    You can decorate those properties in your POCO class which needs to be treated as a nullable field, like this for example

    public class OdooResult
    {
        public int id { get; set; }
    
        [JsonConverter(typeof(FalseToNullConverter))]
        public int? campaign_id { get; set; }
    
        [JsonConverter(typeof(FalseToNullConverter))]
        public Guid? source_id { get; set; }
    
        [JsonConverter(typeof(FalseToNullConverter))]
        public long? medium_id { get; set; }
    
        public List<object> activity_ids { get; set; }
    
        public bool activity_state { get; set; }
    
        [JsonConverter(typeof(FalseToNullConverter))]
        public int? activity_user_id { get; set; }
    
        [JsonConverter(typeof(FalseToNullConverter))]
        public int? activity_type_id { get; set; }
    
        public bool activity_type_icon { get; set; }
    
        [JsonConverter(typeof(FalseToNullConverter))]
        public DateTime? activity_date_deadline { get; set; }
    
        [JsonConverter(typeof(FalseToNullConverter))]
        public DateTime? my_activity_date_deadline { get; set; }
    
        public bool activity_summary { get; set; }
    
        public bool activity_exception_decoration { get; set; }
    
        public bool activity_exception_icon { get; set; }
    
        public bool activity_calendar_event_id { get; set; }
    }
    

    Known limitation

    If you receive true for example for the campaign_id then it will be deserialized as 1. Depending on your requirements this needs to be handled differently.