Ric*_*ast 5 error-handling rust deserialization serde
我正在反序列化一些作为请求传入的 JSON 对象。输入正文是嵌套的,但某些字段有时会因各种原因而格式错误。在那种情况下我仍然想要该物体的其余部分。这并不都必须通过 serde 来完成;但现在发生的情况是,如果单个子字段被搞乱,整个请求就会被丢弃。我想以某种方式仍然反序列化该结果并将该字段标记为错误。如何才能做到这一点?
例如,数据模式可能如下所示:
struct BigNested {
a: Vec<A>,
b: B, // definition omitted
}
struct A {
keep_this: Foo,
trouble: SometimesBad,
}
Run Code Online (Sandbox Code Playgroud)
trouble
这是一个经常出现混乱的领域。我很乐意(例如)变成trouble
aResult<SometimesBad, Whatever>
并从那里处理它,但我不知道如何让 serde 让我这样做。
某些字段有时格式错误
您没有说传入的 JSON 格式有多么错误。假设它仍然是有效的 JSON,您可以使用Serde 的结构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));
}
Run Code Online (Sandbox Code Playgroud)
(功劳不全是我的。Serde的第 1583 期基本上包含了所有内容。)