如何使用Serde解析可能在不失败整个反序列化的情况下无法反序列化的字段? [英] How to use Serde to parse a field that might fail to be deserialized without failing the entire deserialization?

查看:109
本文介绍了如何使用Serde解析可能在不失败整个反序列化的情况下无法反序列化的字段?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在反序列化作为请求进入的一些JSON对象.输入主体是嵌套的,但是某些字段有时由于各种原因而格式错误.在那种情况下,我仍然需要其余的对象.这并不需要全部通过serde完成;但是现在发生的是,如果单个子字段被弄乱了,整个请求将被丢弃.我想以某种方式仍然反序列化该结果,只是将该字段标记为错误.该怎么办?

I am deserializing some JSON objects which come in as requests. The input body is nested, but a certain field is sometimes misformatted for a variety of reasons. In that situation I still want the rest of the object. This doesn't all have to be done through serde; but what is happening now, is that if a single subfield is messed up, the whole request is trashed. I want to somehow still deserialize that result and just mark the field as errored out. How can this be done?

例如数据模式可能看起来像:

E.g. the data schema might look like:

struct BigNested {
    a: Vec<A>,
    b: B, // definition omitted
}

struct A {
    keep_this: Foo,
    trouble: SometimesBad,
}

麻烦是经常被弄乱的字段.我很乐意(例如)将 trouble 转换为 Result< SometimesBad,Whatever> 并从那里进行处理,但我不知道如何让Serde让我这样做.

trouble is the field that's frequently coming in messed up. I would be happy to (e.g.) turn trouble into a Result<SometimesBad, Whatever> and process it from there, but I don't know how to get serde to let me do that.

推荐答案

某些字段有时格式错误

certain field is sometimes misformatted

您没有说传入的JSON的格式如何.假设它仍然是有效的JSON,您可以使用 Serde的结构 flatten

You didn't say how malformed the incoming JSON was. Assuming it's still valid JSON, you can pull this off with Serde's struct flatten and customized deserialization:

  • 自定义反序列化的方式对于有效的JSON输入永远不会失败,尽管如果输入具有意外格式,它可能不会返回预期类型的​​值.

  • The customized deserialization is done in a way that never fails for valid JSON input, although it may not return value of expected type if the input has unexpected format.

但是这些意外字段仍然需要放在某个地方.Serde的结构 flatten 在这里很方便,因为任何 JSON代码片段都可以反序列化为 HashMap< String,Value> .

But these unexpected fields still need to go somewhere. Serde's struct flatten comes in handy here to catch them since any JSON snippet can be deserialized to a 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的问题1583 基本上是一切都有.)

(The credit isn't all mine. Serde's issue 1583 basically has everything.)

这篇关于如何使用Serde解析可能在不失败整个反序列化的情况下无法反序列化的字段?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆