6

I need to serialize objects (OpenTK.Vector2) containing properties with a getter but no setter. I would like these properties to be ignored in general, otherwise I end up with hugely inflated JSON from an object that has two relevant pieces of data (X and Y).

The code:

JsonSerializerSettings settings = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
Vector2 v = new Vector2 { X = 1, Y = 0 };
string json = JsonConvert.SerializeObject(v, settings);

produces the string:

{
   "X" : 1.0,
   "Y" : 0.0,
   "Length" : 1.0,
   "LengthFast" : 1.0016948,
   "LengthSquared" : 1.0,
   "PerpendicularRight" : {
      "X" : 0.0,
      "Y" : -1.0,
      "Length" : 1.0,
      "LengthFast" : 1.0016948,
      "LengthSquared" : 1.0,
      "PerpendicularRight" : {
         "X" : -1.0,
         "Y" : 0.0,
         "Length" : 1.0,
         "LengthFast" : 1.0016948,
         "LengthSquared" : 1.0,
         "PerpendicularRight" : {
            "X" : 0.0,
            "Y" : 1.0,
            "Length" : 1.0,
            "LengthFast" : 1.0016948,
            "LengthSquared" : 1.0
         }
      },
      "Yx" : {
         "X" : -1.0,
         "Y" : 0.0,
         "Length" : 1.0,
         "LengthFast" : 1.0016948,
         "LengthSquared" : 1.0,
         "PerpendicularRight" : {
            "X" : 0.0,
            "Y" : 1.0,
            "Length" : 1.0,
            "LengthFast" : 1.0016948,
            "LengthSquared" : 1.0
         } 
      }
   },
   "PerpendicularLeft" : {
      "X" : 0.0,
      "Y" : 1.0,
      "Length" : 1.0,
      "LengthFast" : 1.0016948,
      "LengthSquared" : 1.0,
      "PerpendicularLeft" : {
         "X" : -1.0,
         "Y" : 0.0,
         "Length" : 1.0,
         "LengthFast" : 1.0016948,
         "LengthSquared" : 1.0,
         "PerpendicularLeft" : {
            "X" : 0.0,
            "Y" : -1.0,
            "Length" : 1.0,
            "LengthFast" : 1.0016948,
            "LengthSquared" : 1.0
         },
         "Yx" : {
            "X" : 0.0,
            "Y" : -1.0,
            "Length" : 1.0,
            "LengthFast" : 1.0016948,
            "LengthSquared" : 1.0
         }
      }
   },
   "Yx" : {
      "X" : 0.0,
      "Y" : 1.0,
      "Length" : 1.0,
      "LengthFast" : 1.0016948,
      "LengthSquared" : 1.0,
      "PerpendicularLeft" : {
         "X" : -1.0,
         "Y" : 0.0,
         "Length" : 1.0,
         "LengthFast" : 1.0016948,
         "LengthSquared" : 1.0,
         "PerpendicularLeft" : {
            "X" : 0.0,
            "Y" : -1.0,
            "Length" : 1.0,
            "LengthFast" : 1.0016948,
            "LengthSquared" : 1.0
         },
         "Yx" : {
            "X" : 0.0,
            "Y" : -1.0,
            "Length" : 1.0,
            "LengthFast" : 1.0016948,
            "LengthSquared" : 1.0
         }
      }
   }
}

How can I get the serializer ignore these other properties?

Little Endian
  • 784
  • 8
  • 19
  • Actually I'm having a hard time deciphering the logic of what was output. The tree for `PerpendicularRight` discludes `PerpendicularLeft` and vice-versa. – Little Endian May 01 '15 at 19:59

1 Answers1

6

Since you can't modify the OpenTK.Vector2 struct to add [JsonIgnore] property to the get-only properties, the easiest way to do this might be to write your own JsonConverter for it:

public class Vector2Converter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(OpenTK.Vector2);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var temp = JObject.Load(reader);
        return new OpenTK.Vector2(((float?)temp["X"]).GetValueOrDefault(), ((float?)temp["Y"]).GetValueOrDefault());
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var vec = (OpenTK.Vector2)value;
        serializer.Serialize(writer, new { X = vec.X, Y = vec.Y});
    }
}

Then use it like:

        var settings = new JsonSerializerSettings();
        settings.Converters.Add(new Vector2Converter());
        Vector2 v = new Vector2 { X = 1, Y = 0 };
        string json = JsonConvert.SerializeObject(v, settings);
        Debug.WriteLine(json);

Which produces

{"X":1.0,"Y":0.0}

But if you really want to ignore all get-only properties everywhere on all classes and structs (which might have unforeseen consequences), see here: Is there a way to ignore get-only properties in Json.NET without using JsonIgnore attributes?.

dbc
  • 104,963
  • 20
  • 228
  • 340
  • Perfect response. Thanks for your time. – Little Endian May 01 '15 at 16:25
  • If I use the `JsonConverter` in conjunction with the `ContractResolver` described in the link, then I get no output at all. The `CreateProperties` method is called twice in this case, the second time with some anonymous type, for which it returns an empty list. – Little Endian May 01 '15 at 17:13
  • 1
    @thethuthinnang - it's probably because all anonymous types such as the one I serialize with `new { X = vec.X, Y = vec.Y}` [have no setters](https://stackoverflow.com/questions/1089406/why-are-the-properties-of-anonymous-types-in-c-sharp-read-only). – dbc May 01 '15 at 17:28
  • 1
    @thethuthinnang - it could be solved by making some tiny nested explicit type inside Vector2Converter with two public properties `X` and `Y`. – dbc May 01 '15 at 17:29