Reputation: 2454
I have JSON configuration files that I deserialize into c# classes. However, sometimes, I have a need to merge certain nodes of the config files. I can't simply serialize object 1 and object 2 and then merge because of the way null and default value handling work (if object 2 has a default value, it won't serialize and overwrite object 1's differing property value). I'd prefer to keep my default and null value handling untouched.
Is there some sort of metadata deserialization method that along with the object, I'd have access to the source json of that particular node? I know this is far reaching, but I'm not quite sure how else to handle my situation.
{
"prop1": "value1",
"prop2": "value2",
"defaultProp4Options": {
"subprop1": "subvalue1",
"subprop2": "subvalue2",
"subprop3": "subvalue3"
},
"prop4": [
{
"subprop4": "subvalue4"
},
{
"subprop2": "diff2",
"subprop3": "diff3",
},
{
"subprop1": "diff1",
"subprop5": "subvalue5",
}
]
}
I'm thinking the only way to do this is to merge prior to deserialization, but I'm a little stuck.
var jfoo = JObject.Parse(myconfigjson);
var defaults = jfoo.Values("defaultProp4Options");
var bars = jfoo.Values("prop4");
// ***********
// How do I merge defaults with each bar (bar has precendence) and replace collection?
// ***********
// Use the new merged json to deserialize
var result = JsonConvert.DeserializeObject<Foo>(jfoo.ToString());
Can anybody get me on the right track?
UPDATE
This gets me there, but let me know if you know of a better way.
var foo = JObject.Parse(s);
var defaults = jfoo.GetValue("defaultProp4Options");
var bars = jfoo.GetValue("prop4");
var j = new JArray();
foreach (var bar in bars)
{
var baseDefaults = defaults.DeepClone() as JObject;
baseDefaults.Merge(bar);
j.Add(baseDefaults);
}
jfoo.Remove("defaultProp4Options");
jfoo.Property("bars").Value = j;
Which results in:
{
"prop1": "value1",
"prop2": "value2",
"prop4": [
{
"subprop1": "subvalue1",
"subprop2": "subvalue2",
"subprop3": "subvalue3",
"subprop4": "subvalue4"
},
{
"subprop1": "subvalue1",
"subprop2": "diff2",
"subprop3": "diff3",
},
{
"subprop1": "diff1",
"subprop2": "subvalue2",
"subprop3": "subvalue3",
"subprop5": "subvalue5"
}
]
}
Upvotes: 2
Views: 1411
Reputation: 7295
After 4th release of Json.Net version 6 it supports Merge operation based on JContainer.Merge
method.
but unfortunately in your sample we can't use the method directly because defaultProp4Options
is an object and prop4
is an array, but if the structure is not going to change heavily we can iterate in prop4
and merge the items instead, here is an example
var jsonObj = JObject.Parse(json);
var def = (JObject)jsonObj["defaultProp4Options"];
var prop4 = jsonObj["prop4"];
for(int i=0;i<prop4.Count();i++)
{
var item = prop4.ElementAt(i);
var cloneDef =(JObject) def.DeepClone();
cloneDef.Merge(item);
item.Replace(cloneDef);
}
var mergedJson = jsonObj.ToString(); //only used to show new json
Console.WriteLine(mergedJson);
var foo = jsonObj.ToObject<Foo>(); //deserializing to foo
and here is the output result
{
"prop1": "value1",
"prop2": "value2",
"defaultProp4Options": {
"subprop1": "subvalue1",
"subprop2": "subvalue2",
"subprop3": "subvalue3"
},
"prop4": [
{
"subprop1": "subvalue1",
"subprop2": "subvalue2",
"subprop3": "subvalue3",
"subprop4": "subvalue4"
},
{
"subprop1": "subvalue1",
"subprop2": "diff2",
"subprop3": "diff3"
},
{
"subprop1": "diff1",
"subprop2": "subvalue2",
"subprop3": "subvalue3",
"subprop5": "subvalue5"
}
]
}
Upvotes: 1