我正在反序列化一些作为请求传入的 JSON 对象。输入正文是嵌套的,但是某个字段有时会因为各种原因格式错误。在那种情况下,我仍然想要该对象的其余部分。这并不都必须通过 serde 来完成;但现在正在发生的事情是,如果一个子字段被搞砸了,整个请求都会被丢弃。我想以某种方式仍然反序列化该结果,并将该字段标记为错误。如何做到这一点?
例如数据模式可能如下所示:
struct BigNested {
a: Vec<A>,
b: B, // definition omitted
}
struct A {
keep_this: Foo,
trouble: SometimesBad,
}
trouble
是经常出现困惑的领域。我很乐意(例如)转 trouble
进入Result<SometimesBad, Whatever>
并从那里处理它,但我不知道如何让 serde 让我这样做。
最佳答案
certain field is sometimes misformatted
您没有说明传入的 JSON 格式有多么畸形。假设它仍然是有效的 JSON,您可以使用 Serde's struct flatten
来解决这个问题和自定义反序列化:
自定义反序列化以一种永远不会对有效 JSON 输入失败的方式完成,但如果输入具有意外格式,它可能不会返回预期类型的值。
但这些意想不到的领域仍然需要去某个地方。 Serde 的结构
flatten
因为 任何 JSON 片段都可以反序列化为HashMap<String, Value>
,所以在这里可以派上用场来捕获它们.
//# serde = { version = "1.0.103", features = ["derive"] }
//# serde_json = "1.0.44"
use serde::{Deserialize, Deserializer, de::DeserializeOwned};
use serde_json::Value;
use std::collections::HashMap;
#[derive(Deserialize, Debug)]
struct A {
keep_this: Foo,
trouble: SometimesBad,
}
#[derive(Deserialize, Debug)]
struct Foo {
foo: i32,
}
#[derive(Deserialize, Debug)]
struct SometimesBad {
inner: TryParse<Bar>,
#[serde(flatten)]
blackhole: HashMap<String, Value>,
}
#[derive(Deserialize, Debug)]
struct Bar {
bar: String,
}
#[derive(Debug)]
enum TryParse<T> {
Parsed(T),
Unparsed(Value),
NotPresent
}
impl<'de, T: DeserializeOwned> Deserialize<'de> for TryParse<T> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
match Option::<Value>::deserialize(deserializer)? {
None => Ok(TryParse::NotPresent),
Some(value) => match T::deserialize(&value) {
Ok(t) => Ok(TryParse::Parsed(t)),
Err(_) => Ok(TryParse::Unparsed(value)),
},
}
}
}
fn main() {
let valid = r#"{ "keep_this": { "foo": 1 }, "trouble": { "inner": { "bar": "one"}}}"#;
println!("{:#?}", serde_json::from_str::<A>(valid));
let extra_field = r#"{ "keep_this": { "foo": 1 }, "trouble": { "inner": { "bar": "one"}, "extra": 2019}}"#;
println!("{:#?}", serde_json::from_str::<A>(extra_field));
let wrong_type = r#"{ "keep_this": { "foo": 1 }, "trouble": { "inner": { "bar": 1}}}"#;
println!("{:#?}", serde_json::from_str::<A>(wrong_type));
let missing_field = r#"{ "keep_this": { "foo": 1 }, "trouble": { "inner": { "baz": "one"}}}"#;
println!("{:#?}", serde_json::from_str::<A>(missing_field));
let missing_inner = r#"{ "keep_this": { "foo": 1 }, "trouble": { "whatever": { "bar": "one"}}}"#;
println!("{:#?}", serde_json::from_str::<A>(missing_inner));
}
(功劳不全是我的。Serde's issue 1583基本上什么都有。)
关于error-handling - 如何在不使整个反序列化失败的情况下使用 Serde 解析可能无法反序列化的字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64114043/