1

I have two messages like so:

string test1 = @"{ ""coords"": { x: 1, y: 2, z: 3 }, ""w"": 4, ""success"": true}";
string test2 = @"{ ""coords"": { x: 1, y: 2, z: 3 }, ""success"": true}";

Given the following classes that I want to deserialize into:

public struct Coordinate
{
    public int x { get; set; }
    public int y { get; set; }
    public int z { get; set; }

    public int w { get; set; }
}

public class MessageBody
{
    [JsonConverter(typeof(JsonCoordinateConverter))]
    public Coordinate Coords;

    public bool Success { get; set; }
}}

Is it possible to write the JsonCoordinateConverter such that it is able to read the w property, which is outside of the context of coords object?

I tried the following:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    Coordinate coords = new Coordinate();
    JObject coordObject = JObject.Load(reader);

    // move to the next token
    reader.Read();
    if (reader.Path == "w")
    {
        coords.w = reader.ReadAsInt32().Value;
    }
    else 
    {
        // for test2, the token here is success,
        // how do I rewind for the regular deserializer to read it?
        reader.Skip();
    }

    coords.x = coordObject["x"].Value<int>();
    coords.y = coordObject["y"].Value<int>();
    coords.z = coordObject["z"].Value<int>();

    return coords;
}

With this approach though, I'm reading over the success property if w is not in the original message, and the regular deserializer does not pick up the success value. So I'd need to somehow peek to check whether w is there or not, or rewind when I don't find it, but can't find a way to do either.

Note: this is a very simplified representation of the issue, the real message and objects are bigger, and the regular deserializer works fine for them, so I'd like to avoid writing custom code for everything and keep it to coords+w only, if at all possible.

Working demo code gist, second assert fails of course.

MarcinJ
  • 3,471
  • 2
  • 14
  • 18
  • 2
    No, there is no way to do that in a converter for `Coordinate`. Note that, according to the [json standard](http://www.json.org/) a JSON object is *an unordered set of name/value pairs*, so the `"w"` property might come first. Instead, you need a converter on the parent object. You could use the pattern from [Custom deserializer only for some fields with json.NET](https://stackoverflow.com/q/41510242/3744182) or [Deserialize two values into the same property](https://stackoverflow.com/a/42006081/3744182) to automatically populate everything except the `"w"` property into `MessageBody`. – dbc Apr 07 '17 at 21:21
  • 1
    @dbc Yes, I know JSON isn't ordered, in this case though it's known and always the same. Anyway, thanks a lot, the second approach - setter on a private property - will work. – MarcinJ Apr 07 '17 at 22:03
  • Glad to help. I'll mark this one as a duplicate then. – dbc Apr 07 '17 at 22:05

0 Answers0