Home > Software engineering >  Newtonsoft.json: If deserialization error, try different class
Newtonsoft.json: If deserialization error, try different class

Time:09-11

I have a class myClass which I have recently refactored. Originally, it contained properties string Category and string Value, and serialized as

{
   "Category": "someCategory",
   "Value": "someValue"
}

After refactoring, it now contains properties Signature Sig and ExtraData Data, where Signature is a class containing the original properties string Category and string Value, so it deserializes as

{
   "Sig":{
      "Category": "someCategory",
      "Value": "someValue"
   },
   "ExtraData": { ... large set of additional data here}
}

myClass is a shared class used extensively throughout my program, usually in the context of List<myClass>, and is serialized as part of saving several different types of larger overarching settings classes. When I try to deserialize these settings files using the updated class definition, the deserializer (of course) fails to deserialize the existing string, resulting in empty lists that had previously been populated.

I am wondering if it's possible to implement the following logic using a JsonConverter or ContractResolver (pseudocode)

///jsonString here should be the fragment of the larger json file containing just the current object

myclass attempt = JsonConvert.DeserializeObject<myClass>(jsonString);

if (attempt == null) // or whichever method is best to determine deserialization success
{
   Signature attempt2 = JsonConvert.DeserializeObject<Signature>(jsonString);
   if (attempt2 != null)
   { 
      myClass converted = new();
      converted.Sig = attempt2;
      return converted;
   }
   else
   {
      return null; // or whatever behavior is used to skip populating the list
   }
}
else
{
   return attempt; // from a settings file which had already been upgraded
}

I tried implementing a JsonConverter but got stuck on the ReadJson() function at object value = reader.Value; - it seemed like value was only generated one line at a time (e.g. in my case as "Category": "someCategory") instead of the entire object, so I couldn't deserialize it to a Signature class as it only contained half of the required data.

Is there a way to implement the desired behavior?

CodePudding user response:

I usually use a JsonConstructor in this case, it will properly deserialize both of your jsons.

    MyClass myClass = JsonConvert.DeserializeObject<MyClass>(json);

public class MyClass
{
    public Sig Sig { get; set; }
    public ExtraData ExtraData { get; set; }
    
    [JsonConstructor]
    public MyClass(Sig Sig, string Category, string Value)
    {
        if (Sig != null) this.Sig = Sig;
        else
        {
            this.Sig = new Sig
            {
                Category = Category,
                Value = Value
            };
        }
    }
    public MyClass() {}
}

public class Sig
{
    public string Category { get; set; }
    public string Value { get; set; }
}
public class ExtraData
{
}
  • Related