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();
}
}