I have some fairly complex JSON and need to use Newtonsoft to deserialize, as JSON.net is not as extensible as Newtonsoft.
My problem is as follows: I have a class, let's call "A", which I use a few places in my app including saving to a DB using EFCore and converting to a binary file. I populate the class using a JSON File, but due to requirements beyond my control I need to keep the default value setter in the class. However, IF the property does NOT exist in the Json we are deserializing, I'd like to use a custom default value.
Example Class:
public class A
{
public int Id { get; } = 0;
public bool IsRequired { get; } = true;
}
And if this is my Json:
[{
"id": 4,
"isRequired": true;
},
{
"id": 7
}]
I'd like to override the isRequired
default to false if the key is not in the json.
var list = JsonConvert.DeserializeObject<List<A>>( -- some settings --);
// list[0]
// - Id = 4
// - IsRequired = true
//
// list[1]
// - Id = 6
// - IsRequired = false
I've been able to get a basic version of this working as described in this SO post, but the deserialization is very simple and breaks immediately with nested properties and complex types my custom contract resolver I have.
Note that I am using .NET 6, and my models are separated from my deserializers.
CodePudding user response:
There are two options using a JsonConverter
for that
The easy way (if you may extend the existing object)
Since you already have written half of the answer within your question "I'd like to override the isRequired default to false" then lets use the intended behavior for overwriting in combination to a customJsonConverter
First lets make the
IsRequired
propertyvirtual
public class A { public int Id { get; set;} = 0; public virtual bool IsRequired { get; set;} = true; }
Afterwards we can inherit and overwrite the default behavior:
private class ADersialize : A { public override bool IsRequired { get; set;} = false; }
With those modifications we can use a custom converter which uses
ADeserialze
:public class AConverter : JsonConverter { public static readonly AConverter Instance = new AConverter(); public override bool CanConvert(Type objectType) { return objectType == typeof(A); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { return serializer.Deserialize<ADersialize>(reader); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { serializer.Serialize(writer, value); } }
And with those changes you can just deserialize it:
var list = JsonConvert.DeserializeObject<List<A>>(x, AConverter.Instance);
Option two is when you cannot modify
A
at all. Then you also need to write a customJsonConverter
and withinReadJson
initializeA
and setIsRequired = false
and afterwards deserialze each field individually.
CodePudding user response:
you just need to add a constructor to your class , since you have only get (read only properties)
var list = JsonConvert.DeserializeObject<List<A>>(json);
//test
json=JsonConvert.SerializeObject(list, Newtonsoft.Json.Formatting.Indented);
}
public class A
{
public int Id { get; } = 0;
public bool IsRequired { get; } = true;
[JsonConstructor]
public A(int Id, bool? isRequired) {
this.Id=Id;
this.IsRequired= isRequired==null ? false: (bool)isRequired;
}
}
result
[
{
"Id": 4,
"IsRequired": true
},
{
"Id": 7,
"IsRequired": false
}
]