Home > front end >  How to deserialize nested array in my case to custom classes?
How to deserialize nested array in my case to custom classes?

Time:01-29

Test1 deserializes msg1 that has a single array (data:[]) successfully. ElementJsonConverter handles the ElementData which is more complicated than in the example.

Test2 tries to deserializes msg2 that has a nested array (data:[[]]). Message2 class has Table class which has List<TableRow> when TableRow is List<ElementData> that I need to populate. I don't understand how to do this. Do I need somehow to have separate converters for Table and TableRow?

Single Array

void Test1()
{
   var msg1 = "{\"type\":\"message1\",\"data\":[{\"name\":\"myname\",\"amount\":0}]";
   var obj = JsonConvert.DeserializeObject<Message1>(msg1);
}

public class Message1
{
    [JsonProperty("type")]
    public string Type { get; set; }
    [JsonProperty("data", ItemConverterType = typeof(ElementJsonConverter))]
    public List<ElementData> Data { get; set; }
}

public abstract class ElementData
{   
    [JsonProperty("amount")]
    public int Amount { get; set; }
}

public class Element : ElementData
{   
    [JsonProperty("name")]
    public string Name{ get; set; }
}

Nested Array

void Test2()
{
   var msg2 = "{\"type\":\"message2\",\"data\":[[{\"name\":\"myname\",\"amount\":0}]]";
   var obj = JsonConvert.DeserializeObject<Message1>(msg2);
}

public class Message2
{
    [JsonProperty("type")]
    public string Type { get; set; }

    [JsonConverter(typeof(TableJsonConverter))]
    [JsonProperty("data")]
    public Table Data { get; set; }
}

public class Table
{
    public List<TableRow> Steps { get; set; }
}

public class TableRow
{
    [JsonProperty(ItemConverterType = typeof(StepElementJsonConverter))]
    public List<ElementData> Elements { get; set; }
}

public class TableJsonConverter : JsonConverter<Table>
{
    public override Table ReadJson(JsonReader reader, Type objectType, Table existingValue, bool hasExistingValue, Newtonsoft.Json.JsonSerializer serializer)
    {          
    }

    public override void WriteJson(...){}
}

CodePudding user response:

For the provided code (without missing converters) you can just deserialize to collection of collection of elements:

public override Table ReadJson(JsonReader reader, Type objectType, Table existingValue, bool hasExistingValue, Newtonsoft.Json.JsonSerializer serializer)
{
    // TODO - handle existing value?
    var deserialize = serializer.Deserialize<Element[][]>(reader); // or ElementData if converter handles it
    return new Table
    {
        Steps = deserialize.Select(x => new TableRow
        {
            Elements = x.ToList<ElementData>()
        })
        .ToList()
    };
    return default;
} 

For more dynamic approach you can use var jArr = JArray.Load(reader) and process it.

CodePudding user response:

IMHO I'd rather to use one root class

public class Message
{
    public string Type { get; set; }

    public List<List<ElementData>> Data { get; set; }

    [JsonConstructor]
    public Message(string type,JToken data)
    {
        Type = type;
        if(type == "message2")
                Data = data.Select(x => x.Select(y => (ElementData)y.ToObject<Element>()).ToList()).ToList();
            else Data = new List<List<ElementData>> { data.Select(x => (ElementData)x.ToObject<Element>()).ToList() };
    }
}

or if you like converters

public class MessageJsonConverter : JsonConverter<Message>
{
    public override Message ReadJson(JsonReader reader, Type objectType, Message existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var data = (JObject)serializer.Deserialize(reader);

        return new Message
        {
            Type = data["type"].ToString(),
            Data = data["type"].ToString()=="message2"
                   ? data["data"].Select(x => x.Select(y => (ElementData)y.ToObject<Element>()).ToList()).ToList()
                   : new List<List<ElementData>> { data["data"].Select(x => (ElementData)x.ToObject<Element>()).ToList() }
        };
    }

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