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.
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.