有没有一种方法可以在不创建细粒度对象的情况下使用Serde反序列化任意JSON数据?

27

我有一个JSON对象,其中包含一些元数据键和大量的数据有效负载。我的服务关心元数据以用于日志记录和路由,但不关心有效负载,除了将有效负载传递给另一个服务外。我将永远不需要出于任何原因查看有效负载的内部。

现在,有效负载在我的结构中表示为serde_json :: Value 。通过分析,我看到(反)序列化Value需要相当长的时间。

在Serde中是否有一种机制可以在不必将其反序列化为组件值的情况下捆绑有效负载,只需稍后重新对其进行序列化即可避免性能成本?

extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

#[derive(Serialize, Deserialize)]
struct DataBlob<'a> {
    id: &'a str,
    priority: u8,
    // payload: OpaqueValue,
}

fn main() {
    let input = r#"{
        "id": "cat",
        "priority": 42,
        "payload": [1, 2, 3, 4]
    }"#;

    let parsed = serde_json::from_str::<DataBlob>(input).expect("Could not deserialize");
    let output = serde_json::to_string(&parsed).expect("Could not serialize");

    assert!(output.contains("payload"));
}

2
换句话说,反序列化idpriority,但不反序列化payload,然后稍后重新序列化一个具有不同id和/或priority,但仍具有相同(已序列化)的payload的对象? - MutantOctopus
@BHustus 是的,那看起来是正确的。另一种用法是将有效载荷移动到新的结构体中,更改元数据的数量和类型,甚至可以单独输出有效载荷而不带任何元数据。 - Shepmaster
1
浏览了一下文档,似乎通过serde_json实现这个功能的唯一方法是创建一个Read的自定义实现,将整个payload值转换为json子字符串,然后使用new将其插入到Deserializer中,类似地,对于序列化,可以使用WriteFormat进行类似操作。我不太熟悉serde,所以不敢将其发布为完整答案。 - MutantOctopus
你要为那个结构体编写自定义的序列化和反序列化函数吗?对于你想检查的那些,可以使用标准的serde_json,而对于DataBlob,则可以使用一大块字节(base 64或其他)作为序列化数据。 - Andrew Mackenzie
1个回答

7

这是在serde_json 1.0.29中添加的类型RawValue。 必须使用raw_value功能启用,然后将其放置在引用后面:

extern crate serde; // 1.0.79
#[macro_use]
extern crate serde_derive; // 1.0.79
extern crate serde_json; // 1.0.30, features = ["raw_value"]

#[derive(Serialize, Deserialize)]
struct DataBlob<'a> {
    id: &'a str,
    priority: u8,
    payload: &'a serde_json::value::RawValue,
}

fn main() {
    let input = r#"{
        "id": "cat",
        "priority": 42,
        "payload": [1, 2, 3, 4]
    }"#;

    let parsed = serde_json::from_str::<DataBlob>(input).expect("Could not deserialize");
    let output = serde_json::to_string(&parsed).expect("Could not serialize");

    assert!(output.contains("payload"));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接