Can I Install Custom JSON Converter for Couchbase Lite .Net?

Third-party libraries that we use in our project contain a couple of unwieldy types that cannot be serialised and deserialised by the default JSON serialisers. My current work-around is to convert them to something that the JSON serialiser understands before adding them to the Document.Properties dictionary. It would, however, be a lot easier if I could install a custom JSON serialiser. Something like

class OneTypeToRuleThemAllConverter : JsonConverter
{
   public override bool CanConvert(Type objectType)
   {
      return objectType == typeof(OneTypeToRuleThemAll);
   }
   
   public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
   {
      ...
   }

   public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
   {
      ...
   }

}

myCouchbaseLiteDatabase.AddSerialiser(new OneTypeToRuleThemAllConverter());

This would, probably, imply that fetching the document it would be more convenient if I could get the data as a JObject instead of a dictionary. In an ideal future I would, of course, prefer a generic GetExistingDocument method so that I could do

var supremeRulerOfTheDatabase = myCouchbaseLiteDatabase.GetExistingDocument<OneTypeToRuleThemAll>(supremeRulerId);

Well, this is something we have planned for a future release but it actually goes one step further than that. We are going to introduce the ability to swap out Newtonsoft JSON.NET for any library as long as it conforms to our interface. I’ve done some initial refactoring but the abstraction is still a bit leaky so it isn’t ready. If you are curious about what this entails, you can have a look at this (on the ForestDB branch that I am currently working on).

The thing is I don’t want these JSON.NET classes to bubble up into the Couchbase Lite API because then users start casting form object to JArray and other bad practices. So the implementation should send back either materialized custom classes, or recursively switch to .NET containers. I have done a bit of work on that as well here.

You can have a look around and even start writing your own serializer if you like, but you will have to rebuild the library since the interface is still internal (and subject to change) at this point in time. Make sure that you replace any intermediate classes with proper .NET ones though because Couchbase Lite is going to be treating them as such.

Thanks Borrden, I like your suggested approach to make it possible to replace the JSON parsing library through a dependency injection. I understand your point about not wanting to expose JSON.NET classes in the Couchbase Lite API. As it happens it would simplify my current work around for misbehaving types, but I am happier to wait for a proper solution instead of an easier way to patch around the problem.

I have had some problems with the implementation not always switching from JObject or JArray to normal .NET containers. At the moment my code contains some ugly conversion like

if (obj is JObject) {
   var jObject = obj as JObject;
   AdditionalInformation = jObject.ToObject<Dictionary<string, string>>();
} else {
   AdditionalInformation = obj as Dictionary<string, string>;
}

I have not had time to investigate this in any detail, so cannot give you any details about when it happens. Would you happen to have any idea about what might be going on? I am not very experienced with .NET so there might be a standard way to handle this scenario that I am not aware of.

It happens more than you think. JSON.NET does not recursively deserialize things, so for example if you have a JObject inside of a JObject and you call ToObject<IDictionary<string, string>> on it, only the outer one will be converted, but the inner one will remain a JObject. I have written a converter to take care of this, but I’ve literally only done it in the last week so it hasn’t made its way into any release, or even the master branch yet (it is on a branch called “json-leak”). As you can imagine it is quite delicate, so I plan to go over it one more time before I merge it.

The dynamicness of the system is to blame. JSON .NET does not want to make any assumptions about what you want to do, and it will choose the most performant and/or literal scenario above all unless you instruct it otherwise. The code you showed here is basically exactly what Couchbase Lite has been doing internally to ensure .NET types where needed. I hope to have this cleaned up for the 1.2 release scheduled for the middle of next month (with a preview release scheduled for the end of this month).

Checking in on this topic since I am running into a similar issue. The library I am uses has DateTimeOffset properties and the default couchbase lite deserializer is changing the properties to DateTime when I read them back in. This loses the timezone information. (see my other post) Did this custom deserializer feature make it into 1.2.0.3?

No, unfortunately this feature has not gone in. Sorry to bring bad news.