2

EDIT 2016-12-05: This was recognized as a bug and fixed: Readonly property corrupts normal property object references. #486

Original post:

I'm just starting out with Json.NET, but have encountered some strange behavior that seems like a bug.

If the Deserializer encounters an object reference ("$ref": "2") that was originally defined in a readonly property (get; only), it fails to deserialize and returns null instead.

Class

public class Parent
{
    public Child ReadOnlyChild
    {
        get
        {
            return Child;
        }
    }

    public Child Child {get; set;}
}
public class Child
{
}

Serialization:

Parent p = new Parent() { Child = new Child() };
JsonConvert.SerializeObject(p, new JsonSerializerSettings()
{ Formatting = Formatting.Indented,
  PreserveReferencesHandling = PreserveReferencesHandling.Objects });

Serialized:

{
  "$id": "1",
  "ReadOnlyChild": {
    "$id": "2",
  },
  "Child": {
    "$ref": "2"
  }
}

Deserialized (& reserialized to show the change):

{
  "$id": "1",
  "ReadOnlyChild": null,
  "Child": null
}

Is this expected behavior, a bug, or am I missing something?

Note that sometimes [JsonProperty(Order = #)] is needed to force the serializer to act on ReadOnlyChild first. Regardless, the above Serialized JSON block will fail to deserialize properly, even if the class has been modified to deserialize Child first.

EDIT: The Child property being nulled is my concern, not ReadOnlyChild being somehow assigned a value by Json.NET

Thanks!

4
  • I never use reference tracking, but looking at your data, it seems that it's creating an "id" for your ReadOnlyChild, you're ordinary Child property is referencing that id, and upon deserialization, since it can't restore ReadOnlyChild, the whole reference tracking business get's all f'ed up. Commented Feb 12, 2015 at 23:11
  • @KirkWoll: That was the conclusion I came to, as well. I understand not being able to assign the Child object to ReadOnlyChild (there's no set; after all), but it throws away the object rather than waiting until the Child property, when it's referenced again. Commented Feb 12, 2015 at 23:14
  • 1
    this is pure speculation on my part, but I suspect what's happening is that json.net successfully deserializaes the value for ReadOnlyChild, tries to place it inside that property -- fails, because it's not writable -- and ultimately leaves a reference (in its internal model) that the value for id "2" is now contained inside ReadOnlyChild (which has no value since the assignment failed). It then gets to the Child's value, "$ref": "2", tries to resolve it as the value of ReadOnlyChild, and sets its value to null as well. Commented Feb 12, 2015 at 23:19
  • 1
    @Shoebox Thanks for coming back to update your question. Commented Dec 6, 2016 at 6:45

1 Answer 1

1

Have you considered just preventing that property from being serialized by Json.Net?

public class Parent
{
    [JsonIgnore] 
    public Child ReadOnlyChild
    {
        get
        {
            return Child;
        }
    }

    public Child Child {get; set;}
}
Sign up to request clarification or add additional context in comments.

4 Comments

This is a good workaround, and will likely be my ultimate solution.
Good if you don't require the ReadOnly field within the Json. Not so good if you do require it, but want to ignore the value upon it's return.
@Shoebox I'd argue it's more than a workaround :D ReadOnlyChild in this case is a computed value, no need to serialize it at all
The issue has been fixed. I edited the OP to reflect this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.