JsonSerializer support for circular references (original) (raw)

Object/collection graphs containing circular references (or multiple references to the same entity), can be handled in a few different ways when serializing/deserializing to/from JSON.

Best practice is naturally to avoid graphs with circular references when using JSON serialization, but techniques to deal with it exist, and some times it may be needed. We use it a few places in our software.

NewtonSoft.Json supports this, and I guess it is a goal for System.Text.Json to make the feature gap with NewtonSoft as small possible.

During serialization, when an object/collection that has already been serialized is referenced for the second time or more, the common technique I've seen is to replace the repeated objects/collection in the JSON with a

{ "$ref": "some-sort-of-pointer" }

Some use JSONPath to reference the object/array serialized previously in the JSON document.

NewtonSoft.Json uses a different techique with specific serialization settings: It adds an extra "$id" property to all serialized objects in the JSON document, and the "$ref" value is the "$id" property of the object/array serialized previously.

Example using NewtonSoft.Json:

using System; using System.Collections.Generic; using Newtonsoft.Json;

namespace CircularSerialization { public class Bike { public List Tires { get; set; } = new List(); }

public class Tire
{
    public Bike Bike { get; set; }
}

static class Program
{
    static void Main()
    {
        var bike = new Bike();
        bike.Tires.Add(new Tire { Bike = bike });
        bike.Tires.Add(new Tire { Bike = bike });

        var settings = new JsonSerializerSettings
        {
            PreserveReferencesHandling = PreserveReferencesHandling.Objects,
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore
        };
        var serialized = JsonConvert.SerializeObject(bike, settings);

        Console.Write(serialized);
        // {"$id":"1","Tires":[{"$id":"2","Bike":{"$ref":"1"}},{"$id":"3","Bike":{"$ref":"1"}}]}
    }
}

}

I guess that if System.Text.Json.JsonSerializer will support circular/multiple references, some more memory allocation will be required during serialization/deserialization when the setting is switched on (so such a setting should naturally be off by default).

Is there a plan to support options for handling circular references in JsonSerializerSettings?
And if so, will you support the "$id" technique or the JSONPath techique, or maybe support both?

Reference:
https://github.com/douglascrockford/JSON-js/blob/master/cycle.js