Reputation: 772
I keep running into the situation where I want to deserialize some JSON into a type that doesn't exactly match the structure of the JSON. For example, if I have JSON like this:
"foo": {
"bar": {
"1": 10,
"4": 20,
"3": 30,
"2": 40,
"5": 50
},
}
Then I would need something like this:
class Bar
{
[JsonProperty]
int One;
[JsonProperty]
int Two;
[JsonProperty]
int Three;
[JsonProperty]
int Four;
[JsonProperty]
int Five;
}
class Foo
{
[JsonProperty]
Bar bar;
}
But what if I want to turn it into this?
class Foo
{
int[] values;
}
where it converts the keys to 0-based indices by subtracting 1 from each one and making an array out of it? How can I do this?
I have many other examples of this kind of custon deserialization, but I'll post one other just for the sake of illustration, as I don't want a solution that is tailored to this exact example, but rather something I can generalize.
"foo": {
"bar": [
{
// Bunch of unimportant stuff
},
{
// Something about the structure of this object alerts me to the fact that this is an interesting record.
"baz": 12
},
{
// Bunch of unimportant stuff
}
]
}
And I want to turn this into:
class Foo
{
int baz;
}
I've looked at a few examples of CustomCreationConverters, such as this, but I was unable to adapt the solution presented there to either of the above situations.
Upvotes: 3
Views: 6143
Reputation: 276
// Something about the structure of this object alerts me to the fact that this is an interesting record.
I don't think the structure of a JSON object should tell anything about its "importance". Either the client should not send any irrelevant information, or you have to write custom code somewhere in your application that selects relevant information from your JSON object. Business rules should determine the importance of data. Treat JSON as what it is, simple data.
As for your first example, you can handle the problem like this using CustomCreationConverters (as you mentioned) and LINQ to JSON:
public class Foo
{
public int[] Values { get; set; }
}
public class FooConverter : CustomCreationConverter<Foo>
{
public override Foo Create(Type objectType)
{
return new Foo();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// Load JObject from stream
JObject jObject = JObject.Load(reader);
// Create target object based on JObject
Foo target = Create(objectType);
// get the properties inside 'bar' as a list of JToken objects
IList<JToken> results = jObject["foo"]["bar"].Children().ToList();
IList<int> values = new List<int>();
// deserialize the tokens into a list of int values
foreach (JToken result in results)
{
int val = JsonConvert.DeserializeObject<int>(result.First.ToString());
values.Add(val);
}
target.Values = values.ToArray();
return target;
}
}
Use it like this:
string fooText = @"{'foo': {
'bar': {
'1': 10,
'4': 20,
'3': 30,
'2': 40,
'5': 50
},
}
}";
Foo foo = JsonConvert.DeserializeObject<Foo>(fooText, new FooConverter());
You can learn more about CustomCreationConverters and how to deserialize partial JSON fragments in the JSON.NET documentation:
http://www.newtonsoft.com/json/help/html/CustomCreationConverter.htm
http://www.newtonsoft.com/json/help/html/SerializingJSONFragments.htm
Upvotes: 3