Alexandru
Alexandru

Reputation: 12912

Deserialize this object with Json.NET

I want to have two test methods pass:

[TestMethod]
public void TestDeserializationSingleArray()
{
    // metaGrids is an array of arrays.
    var data = @"{
                    ""metaGrids"": [
                        [0, 0, 0],
                        [0, 0, 1],
                        [0, 0, 2]
                    ]
                }";
    var result = JsonConvert.DeserializeObject<Data>(data);
}

[TestMethod]
public void TestDeserializationMultipleArrays()
{
    // metaGrids is now an array of an array of arrays.
    var data = @"{
                    ""metaGrids"": [
                        [
                            [0, 0, 0],
                            [0, 0, 1],
                            [0, 0, 2]
                        ],
                        [
                            [0, 0, 0],
                            [0, 0, 1],
                            [0, 0, 2]
                        ]
                    ]
                }";
    var result = JsonConvert.DeserializeObject<Data>(data);
}

My object looks like this:

public class Data
{
    [JsonConverter(typeof(MetagridsDataConverter))]
    public int[][][] metaGrids;
}

I am trying to use a data converter class to make it work in both situations, but this is failing for me:

public class MetagridsDataConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return null;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {

    }
}

How can I code my converter so that it will work in both situations? In my above logic I keep getting this error (even though I'm just trying to baseline a case where I can get the converter to trigger properly):

Newtonsoft.Json.JsonSerializationException: Unexpected token when deserializing object: StartArray. Path 'metaGrids[0]', line 3, position 33.

Upvotes: 0

Views: 238

Answers (1)

orhtej2
orhtej2

Reputation: 2165

Based on idea in this answer I came up with the following:

public class Data
{
    [JsonConverter(typeof(SingleOrArrayConverter))]
    public int[][][] metaGrids;
}

class SingleOrArrayConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(List<List<List<int>>>));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        if (token.Type == JTokenType.Array)
        {

            switch (Dimensions(token))
            {
                case 3:
                    return token.ToObject<int[][][]>();
                case 2:
                    return new int[][][] { token.ToObject<int[][]>() };
            }
        }
        throw new InvalidOperationException("Data is not in a standard supported format.");
    }

    private static int Dimensions(JToken token)
    {
        if (token.Type != JTokenType.Array)
            return 0;
        return 1 + Dimensions(token.First);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Upvotes: 1

Related Questions