0

JSON.NET (using the setting PreserveReferencesHandling = PreserveReferencesHandling.Objects) serializes a reoccurring object inline on first occurrence and serialzes it as JSON reference on subsequent occurrences. I'm guessing this is done to avoid forward references.

For example:

class Person
{
    public string Name { get; set; }
    public Person Mother { get; set; }
}

var joni = new Person { Name = "Joni" };
var james = new Person { Name = "James", Mother = joni };

var people = new List<Person> { james, joni };

var json = JsonConvert.SerializeObject(people, Formatting.Indented,
    new JsonSerializerSettings {
       PreserveReferencesHandling = PreserveReferencesHandling.Objects });

results in the following:

[
  {
    "$id": "1",
    "Name": "James",
    "Mother": {
      "$id": "2",
      "Name": "Joni",
      "Mother": null
    }
  },
  {
    "$ref": "2"
  }
]

Instead, I'd like to get this:

[
  {
    "$id": "1",
    "Name": "James",
    "Mother": {
      "$ref": "2"
    }
  },
  {
    "$id": "2",
    "Name": "Joni",
    "Mother": null    
  }
]

Although both are effectively equal, I find the second much more sensible, especially when editing the JSON data by hand (which is a use case for me in this matter).

Is there a way of controlling which instance is serialized as a reference or am I stuck with this first-occurrence behavior?

EDIT

I've tried deserializing the desired JSON and found that JSON.NET doesn't do that properly because of the forward reference.

Sandor Drieënhuizen
  • 6,310
  • 5
  • 37
  • 80
  • 2
    You're stuck with it. To do what you want, Json.NET would be unable to do a single-pass streaming read & parse of JSON. It would need to load the entire contents into memory (say, into a `JToken` hierarchy), create a lookup database, then deserialize. I suppose you could do something like that: serialize to `JToken`, move `"$id"` nodes from first occurrence to shallowest occurrence, then save; then later do the reverse for deserialization. – dbc Jan 08 '16 at 11:37
  • 1
    @dbc Thanks, I guess I'd better let it go since the trouble doesn't seem to be worth it this time. – Sandor Drieënhuizen Jan 08 '16 at 12:51

1 Answers1

-2

What is going on there is that you are instancing a Person variable inside your Person variable. So when you create the "son":

class Person
{
    public string Name { get; set; }
    public Person Mother { get; set; }
}

You are creating a Mother variable inside, that is a Person type variable, and has all the attributes that a regular Person variable would have, with the resulting JSON file you are obtaining.

Instead of doing that, you can try to create a new class "Mother" that inherits from the class "Person" and only has the ID attribute, so when you create the JSON file, you will obtain the expected result.

Nacho DP
  • 13
  • 5
  • The $id attribute is added by the serializer and is not in the Person class example shown, and hence wouldn't be in the derived Mother class you describe. – Kevin Stephenson Nov 25 '19 at 10:02