Reputation: 3079
I am using this solution:
Is there a way to omit wrapper/root objects when deserializing objects with Serde?
to raise float values out of nested json structures:
Here is the JSON
"activitiesWon": {
"statId": "activitiesWon",
"basic": {
"value": 3.0,
"displayValue": "3"
}
},
And here is the data structure and customer deserializer:
#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy)]
pub struct PvpStatsData {
#[serde(rename = "activitiesWon", deserialize_with="property_to_float")]
pub activities_won:f32,
}
pub fn property_to_float<'de, D>(deserializer: D) -> Result<f32, D::Error>
where D: serde::de::Deserializer<'de>,
{
#[derive(Deserialize)]
struct Outer {
pub basic: Inner,
}
#[derive(Deserialize)]
struct Inner {
pub value: f32,
}
let helper = Outer::deserialize(deserializer)?;
Ok(helper.basic.value)
}
This works great. However, some of the structures / properties might not exist, and thus their field signature looks like this, with the custom deserializer which either returns a Option, or None:
#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy)]
pub struct PvpStatsData {
#[serde(rename = "bestSingleGameKills", deserialize_with="property_to_option_float")]
pub best_single_game_kills:Option<f32>,
}
pub fn property_to_option_float<'de, D>(deserializer: D) -> Result<Option<f32>, D::Error>
where D: serde::de::Deserializer<'de>,
{
println!("PARSER");
#[derive(Deserialize, Debug, )]
struct Outer {
pub basic: Inner,
}
#[derive(Deserialize, Debug, )]
struct Inner {
pub value: f32,
}
Option::<Outer>::deserialize(deserializer).map(|o:Option<Outer>| match o {
Some(e) => {
println!("{:?}", e);
Some(e.basic.value)
},
None => None,
})
}
However, when parsing, if the property doesn't exist in json, then I get a parse error:
serde_json::Error : Error("missing field `bestSingleGameKills`", line: 1, column: 4358)
and my custom de-serialization method is never called.
Anyone know why the de-serialization method is not called? and / or how I can get it to be called when the property doesn't exist? I have other deserializers that can deal with Optional results, but I suspect this has something to do with the combination of the nested json and option.
Ive posted a playground of the example here: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=022d7ca3513e411644d186518d177645
(just uncomment the second json block to see the issue)
Upvotes: 1
Views: 2634
Reputation: 790
The default
field attribute should work (I'm assuming you are ok with best_single_game_kills defaulting to None
when it is absent in the json).
#[derive(Deserialize, Debug, Default, Clone, Copy)]
pub struct PvpStatsData {
#[serde(default, rename = "activitiesWon", deserialize_with="property_to_float")]
pub activities_won:f32,
#[serde(default, rename = "bestSingleGameKills", deserialize_with="property_to_option_float")]
pub best_single_game_kills:Option<f32>,
}
Upvotes: 2