Home > Back-end >  Avoid recursion with custom system.text.json converter
Avoid recursion with custom system.text.json converter

Time:08-14

On one of my classes I would like to do some post-deserialization processing.

The naive solution is

  [JsonConverter(typeof(MyClassFormatter))]
  public class MyClass { 
  
    internal void PostSerialisation()
    {
      //do stuff
    }

  }

  public class MyClassFormatter : JsonConverter<MyClass>
  {
    public override MyClass Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
      var result = JsonSerializer.Deserialize<MyClass>(ref reader, options);
      result.PostSerialisation();
      return result;
    }

    public override void Write(Utf8JsonWriter writer, MyClass value, JsonSerializerOptions options)
    {
      JsonSerializer.Serialize(writer, value, options);
    }
  }

This does not work, obviously, because it is recursive. As I have attached my converter to the class, when I call JsonSerializer.Serialize(...) or JsonSerializer.Deserialize my customer formatter is called and well, you can see where this is going.

Does anyone know of a way of calling JsonSerializer.Serialize or JsonSerializer.Deserialize that ignores my custom formatter and does the default serialization or deserialization?

Of course I could re-implement the serialization/deserialization code but it seems likely that there must be a more elegant solution. This must be quite a common scenario.

CodePudding user response:

Commenter dbc confirmed what I think I had already discovered, that once you have attached a custom converter to a class this problem is difficult to avoid.

However the same commenter pointed out that I was asking the wrong question, and that instead of a custom converter I should implement IJsonOnDeserialization, which worked well.

CodePudding user response:

As far as I know as of .NET 6 there's no way to get the default serialization one you have attached a JsonConverter to the class itself. The serializer will always use the converter when serializing or deserializing. See How to use default serialization in a custom System.Text.Json JsonConverter? for confirmation.

However, in your example it appears you only want to call some postprocessing method after serialization is complete:

public override MyClass Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
  var result = JsonSerializer.Deserialize<MyClass>(ref reader, options);
  result.PostSerialisation();
  return result;
}

This can be done in .NET 6 and later without needing a converter by implementing the IJsonOnDeserialized interface:

public class MyClass : IJsonOnDeserialized 
{
    void IJsonOnDeserialized.OnDeserialized() => PostSerialisation();

    internal void PostSerialisation()
    {
        //do stuff
    }
}

This interface is one of 4 interfaces that, when implemented, cause a callback to be made before or after serialization or deserialization. They are a replacement for Newtonsoft's serialization callbacks:

Note that all four interfaces have the following restriction:

This behavior is only supported on types representing JSON objects. Types that have a custom converter or represent either collections or primitive values do not support this behavior.

Demo fiddle here: https://dotnetfiddle.net/42uzer.

  • Related