1

I am using JSON.NET to serialize and deserialize an object. This object is essentially a grid for a puzzle, and contains 3 main properties. Squares, Vertices and Edges.

Example puzzle

public class Puzzle
{
    public Size Size { get; set; }
    public List<Edge> Edges { get; set; }
    public Square[][] Squares { get; set; }
    public Vertex[][] Vertices { get; set; }

    // ...
}

The thing is, all 3 of these types have references to each other. For example, one Edge remembers which two Vertices it is connecting to each other. And one square knows about his neighbor squares, and the edge that separates it from each of them

public abstract class Edge
{
    public Vertex OriginVertex { get; set; }
    public Vertex DestinationVertex { get; set; }
    public Square LeftSquare { get; set; }
    public Square RightSquare { get; set; }
    public EdgeDirection Direction { get; set; }
    
    // ...
}

I am using JSON.NET to serialize this puzzle type, and I am using preserving all references, in order for this structure to be able to make the round trip.

private JsonSerializer _serializer = new JsonSerializer()
{
    Formatting = Formatting.Indented,
    PreserveReferencesHandling = PreserveReferencesHandling.All,
    ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
    Converters = { new ArrayReferencePreservingConverter()},
    TypeNameHandling = TypeNameHandling.Auto
};

This leads to json that has objects with $id properties, and in other places objects that are only defined as $ref to avoid duplication.

The problem is: Since Serialization is Depth-first, this means that as soon as one of the Puzzle Properties is getting serialized, through a large loop of circular dependencies, every single Vertex/Square/Edge gets serialized in there, as sub-elements of whichever property is getting serialized first. This leads to insane depth in the json file, and even if there weren't code problems, it would be quite ugly and very difficult to work with.

Horribly deep json

Then, when this first property is done serializing, the next two properties are very flat, and only references, because all of their objects have been hit once in the deep spaghetti prior.

The other main properties are only references

What I would like, is for all 3 main properties to Serialize themselves Breadth-First. This would allow every object to appear exactly one-depth below the Puzzle itself, close to the root, and then these objects could refer to each other through the $ref and $id values.

This would significantly reduce the depth of my json file, helping both with code and readability. I essentially have a structure that has a depth of 5 or 6 at most, yet with my current serialization, my depth grows with the size of the puzzle instead of being constant based on my code.

It does not help to re-order the main properties in the Puzzle, as all 3 of them refer to each other and the problem remains the same. Whichever one is serialized first ends up serializing everything inside itself.

One way to solve this problem would be to add an attribute to some properties, that says "only serialize as a $ref, not as the full object", but I was not able to find such an attribute. If this is possible, I would love to know how.

public abstract class Edge
{
    [JsonSerializeAsReferenceIfPossible]
    public Vertex OriginVertex { get; set; }

    [JsonSerializeAsReferenceIfPossible]
    public Vertex DestinationVertex { get; set; }

    [JsonSerializeAsReferenceIfPossible]
    public Square LeftSquare { get; set; }

    [JsonSerializeAsReferenceIfPossible]
    public Square RightSquare { get; set; }

    public EdgeDirection Direction { get; set; }
}

If the above is not possible, I am open to any idea or suggestion as to how to achieve this fixed-depth json that would be ideal both for human and machine readability.

Kaito Kid
  • 983
  • 4
  • 15
  • 34
  • You can't make Json.NET serialize references breadth-first because it is a single pass serializer / deserializer, and depth first reflects the order in which objects happen to be encountered on that single pass. If you don't want that, you will need to change the order in which objects are encountered, e.g. by using a converter that writes out the linkages after all the objects, instead of inside the objects. See e.g. [JSON.NET StackOverflowException while serialization](https://stackoverflow.com/a/41841581/3744182). – dbc Nov 09 '22 at 12:55

0 Answers0