【问题标题】:How to properly handle empty, null and valid JSON?如何正确处理空、null 和有效的 JSON?
【发布时间】:2021-11-26 04:24:37
【问题描述】:

我需要在 Rust 中将 JSON 文件反序列化为 NoneSome(T)。我们使用的源将在不存在值时提供null 或空的“{}”JSON 字段。我想同时处理 None 的情况,并且仅在 JSON 字段不为 null 或为空时反序列化。

input: {"test": null} -> output: {"test": None}
input: {"test": {}} -> output: {"test": None}
input: {"test": {"valid_json": 42}} -> output: {"test": {"valid_json": 42}}

我能找到的所有答案都针对一种情况或另一种情况,但不能同时解决这两种情况。

【问题讨论】:

    标签: serialization rust deserialization option serde


    【解决方案1】:

    This page 告诉您如何实现自定义映射反序列化器,这需要自定义visit_map 如何从输入数据中生成键值对。我基本上复制了该页面并制作了一个最小的示例来实现您正在寻找的内容。 Link to playground.

    use std::fmt;
    use std::marker::PhantomData;
    
    use serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
    use serde_json::Value as JsonValue;
    use std::collections::HashMap;
    
    #[derive(Debug)]
    struct MyMap(HashMap<String, JsonValue>);
    
    impl MyMap {
        fn with_capacity(capacity: usize) -> Self {
            Self(HashMap::with_capacity(capacity))
        }
    }
    
    struct MyMapVisitor {
        marker: PhantomData<fn() -> MyMap>,
    }
    
    impl MyMapVisitor {
        fn new() -> Self {
            MyMapVisitor {
                marker: PhantomData,
            }
        }
    }
    
    impl<'de> Visitor<'de> for MyMapVisitor {
        // The type that our Visitor is going to produce.
        type Value = MyMap;
    
        // Format a message stating what data this Visitor expects to receive.
        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a very special map")
        }
    
        // Deserialize MyMap from an abstract "map" provided by the
        // Deserializer. The MapAccess input is a callback provided by
        // the Deserializer to let us see each entry in the map.
        fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
        where
            M: MapAccess<'de>,
        {
            let mut map = MyMap::with_capacity(access.size_hint().unwrap_or(0));
    
            // While there are entries remaining in the input, add them
            // into our map. Empty Objects get turned into Null.
            while let Some((key, value)) = access.next_entry()? {
                let value = match value {
                    JsonValue::Object(o) if o.is_empty() => JsonValue::Null,
                    _ => value,
                };
                map.0.insert(key, value);
            }
    
            Ok(map)
        }
    }
    
    // This is the trait that informs Serde how to deserialize MyMap.
    impl<'de> Deserialize<'de> for MyMap {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: Deserializer<'de>,
        {
            // Instantiate our Visitor and ask the Deserializer to drive
            // it over the input data, resulting in an instance of MyMap.
            deserializer.deserialize_map(MyMapVisitor::new())
        }
    }
    
    fn main() -> serde_json::Result<()> {
        let json_str = r#"{"a": null, "b": {}, "c": {"valid_json": 42}}"#;
        let v: MyMap = serde_json::from_str(json_str)?;
        println!("{:?}", v);
        Ok(())
    }
    

    这会打印出MyMap({"b": Null, "c": Object({"valid_json": Number(42)}), "a": Null}),我相信这就是您所追求的。

    【讨论】:

      【解决方案2】:
      use serde::{Deserialize, Deserializer};
      
      #[derive(Deserialize, Debug, PartialEq)]
      struct Foo {
          #[serde(deserialize_with = "object_empty_as_none")]
          bar: Option<Bar>,
      }
      
      #[derive(Deserialize, Debug, PartialEq)]
      struct Bar {
          inner: u32,
      }
      
      pub fn object_empty_as_none<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
      where
          D: Deserializer<'de>,
          for<'a> T: Deserialize<'a>,
      {
          #[derive(Deserialize, Debug)]
          #[serde(deny_unknown_fields)]
          struct Empty {}
      
          #[derive(Deserialize, Debug)]
          #[serde(untagged)]
          enum Aux<T> {
              T(T),
              Empty(Empty),
              Null,
          }
      
          match Deserialize::deserialize(deserializer)? {
              Aux::T(t) => Ok(Some(t)),
              Aux::Empty(_) | Aux::Null => Ok(None),
          }
      }
      
      fn main() {
          let data = r#"{"bar": null}"#;
          let v: Foo = serde_json::from_str(data).unwrap();
          assert_eq!(v, Foo { bar: None });
      
          let data = r#"{"bar": {}}"#;
          let v: Foo = serde_json::from_str(data).unwrap();
          assert_eq!(v, Foo { bar: None });
      
          let data = r#"{"bar": {"inner": 42}}"#;
          let v: Foo = serde_json::from_str(data).unwrap();
          assert_eq!(
              v,
              Foo {
                  bar: Some(Bar { inner: 42 })
              }
          );
      
          let data = r#"{"bar": {"not_inner": 42}}"#;
          let v: Result<Foo, _> = serde_json::from_str(data);
          assert!(v.is_err());
      }
      

      对于大多数情况应该足够了。如果您愿意,请删除 Empty 上的 #[serde(deny_unknown_fields)]

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-27
        • 2021-12-14
        • 1970-01-01
        • 1970-01-01
        • 2018-06-04
        • 2018-04-01
        相关资源
        最近更新 更多