I have some data stored as Json. One property in the data is either an integer (legacy data) like so:
"Difficulty": 2,
Or a complete object (new versions):
"Difficulty": {
"$id": "625",
"CombatModifier": 2,
"Name": "Normal",
"StartingFunds": {
"$id": "626",
"Value": 2000.0
},
"Dwarves": [
"Miner",
"Miner",
"Miner",
"Crafter"
]
},
I am trying to write a custom converter for the type that allows deserialization of both versions.
This is C#, using the latest version of newtonsoft.json.
I've written a converter, and deserializing the integer format is trivial - it's only the mix that is causing me trouble. The only way I can think to check is to try and fail; but this appears to leave the reader in an unrecoverable state. Also, calling deserialize in the catch block leads to an infinite loop.
public class DifficultyConverter : 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)
{
try
{
var jObject = serializer.Deserialize<JValue>(reader);
if (jObject.Value is Int32 intv)
return Library.EnumerateDifficulties().FirstOrDefault(d => d.CombatModifier == intv);
else
return null;
}
catch (Exception e)
{
return serializer.Deserialize<Difficulty>(reader);
}
}
public override bool CanWrite
{
get { return false; }
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Difficulty);
}
}
Ideally I would be able to serialize into the new format always, and still support reading both formats. A couple of other options include:
- Creating another serializer object that does not include the custom converter and calling it from the catch block.
- Detecting out of date files at load and modifying the text before attempting to deserialize.
Kind of want to avoid those tho.