首页 > 解决方案 > 通过 serde 捕获原始有效载荷

问题描述

我想知道是否有办法使用 serde_json 保留原始字符串?考虑这个例子:

#[derive(Debug, Serialize, Deserialize)]
struct User {
    #[serde(skip)]
    pub raw: String,
    pub id: u64,
    pub login: String,
}
{
  "id": 123,
  "login": "johndoe"
}

我的结构最终会包含这样的值:

User {
    raw: String::from(r#"{"id": 123,"login": "johndoe"}"#),
    id: 1,
    login: String::from("johndoe")
}

目前,我通过反序列化为Value,然后将此值反序列化到User结构中并将 Value 分配给该raw字段来做到这一点,但这似乎不对,也许有更好的方法吗?

标签: rustserdeserde-json

解决方案


此解决方案使用RawValuefrom 类型serde_json首先获取原始输入字符串。然后Deserializer从该字符串创建一个新的以反序列化该User类型。

该解决方案可以通过Box<serde_json::value::RawValue>用作中介类型与读取器一起使用,也可以通过用作中介来与从输入借用的结构一起使用&'de serde_json::value::RawValue。您可以通过(取消)注释该borrow字段在解决方案中对其进行测试。

use std::marker::PhantomData;

#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[serde(remote = "Self")]
struct User<'a> {
    #[serde(skip)]
    pub raw: String,
    pub id: u64,
    pub login: String,
    // Test for borrowing input data
    // pub borrow: &'a str,
    #[serde(skip)]
    pub ignored: PhantomData<&'a ()>,
}

impl serde::Serialize for User<'_> {
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        Self::serialize(self, serializer)
    }
}

impl<'a, 'de> serde::Deserialize<'de> for User<'a>
where
    'de: 'a,
{
    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        use serde::de::Error;

        // Deserializing a `&'a RawValue` would also work here
        // but then you loose support for deserializing from readers
        let raw: Box<serde_json::value::RawValue> = Box::deserialize(deserializer)?;
        // Use this line instead if you have a struct which borrows from the input
        // let raw = <&'de serde_json::value::RawValue>::deserialize(deserializer)?;

        let mut raw_value_deserializer = serde_json::Deserializer::from_str(raw.get());
        let mut user =
            User::deserialize(&mut raw_value_deserializer).map_err(|err| D::Error::custom(err))?;
        user.raw = raw.get().to_string();
        Ok(user)
    }
}

fn main() {
    // Test serialization
    let u = User {
        raw: String::new(),
        id: 456,
        login: "USERNAME".to_string(),
        // Test for borrowing input data
        // borrow: "foobar",
        ignored: PhantomData,
    };
    let json = serde_json::to_string(&u).unwrap();
    println!("{}", json);

    // Test deserialization
    let u2: User = serde_json::from_str(&json).unwrap();
    println!("{:#?}", u2);
}

在操场上测试


推荐阅读