In my current project I have the problem that I end up in an infinite loop when trying to convert an Item
or any of its subclasses like ArmorItem
.
To detect which type of Item
I have to deserialize I use a custom JsonConverter
called ItemConverter
.
Item.cs:
[JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(ItemConverter))]
public class Item
{
[JsonProperty("id")] public int Id { get; }
[JsonProperty("type")] public string ItemType { get; }
[JsonConstructor]
public Item(int id, string itemType)
{
Id = id;
ItemType = itemType;
}
}
ArmorItem.cs
[JsonObject(MemberSerialization.OptIn)]
public sealed class ArmorItem : Item
{
[JsonProperty("defense")] public int Defense { get; }
[JsonConstructor]
public ArmorItem(int id, string itemType, int defense) : base(id, itemType)
{
Defense = defense;
}
}
ItemConverter.cs
public sealed class ItemConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject item = JObject.Load(reader);
switch (item["type"].Value<string>())
{
case "Armor":
return item.ToObject<ArmorItem>();
default:
return item.ToObject<Item>();
}
}
public override bool CanConvert(Type objectType)
=> typeof (Item).IsAssignableFrom(objectType);
}
I'm usually getting the json data from the web and directly use the WebResponse.GetResponseStream
stream to deserialize the data.
using (HttpWebResponse resp = (HttpWebResponse) req.GetResponse())
using (JsonTextReader reader = new JsonTextReader(new StreamReader(resp.GetResponseStream())))
{
return new JsonSerializer().Deserialize<Item>(reader);
}
I know why this loop occurs but I can't fix it.
However I noticed when deserializing the json data in a different way the problem doesn't occur.
(Item
was altered for this by removing the JsonConverter
attribute)
string json = "SOME JSON DATA HERE";
Item item = JsonConvert.DeserializeObject<Item>(json, new ItemConverter());
Unfortunately I cannot fix the existing code using streams and I don't want to temporarily store the incoming json data into a string to be able to use the working code.
Any ideas how to break the loop?
Another way is to use serializer.Populate()
:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject item = JObject.Load(reader);
switch (item["type"].Value<string>())
{
case "Armor":
var armorItem = new ArmorItem();
serializer.Populate(item.CreateReader(), armorItem);
return armorItem;
default:
var defaultItem = new Item();
serializer.Populate(item.CreateReader(), defaultItem);
return defaultItem;
}
}
More infos at https://gist.github.com/chrisoldwood/b604d69543a5fe5896a94409058c7a95
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With