Is there a way of making serde_json deserialize strictly?
Asked Answered
H

1

5

What I mean is that if 2 objects overlaps on some of the attributes is there a way to try to match all of them? For example:

use serde::{Serialize, Deserialize};
use serde_json; // 1.0.47; // 1.0.104

#[derive(Serialize, Deserialize, Debug)]
pub struct A {
    pub item_1: i32,
    pub item_2: i32,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct B {
    pub item_1: i32,
    pub item_2: i32,
    pub item_3: i32,
}

fn main() {
    let json_data = r#"{"item_1" : 10, "item_2" : 100, "item_3" : 1000}"#;
    if let Ok(data) = serde_json::from_str::<A>(json_data) {
        println!("{:?}", data);
    } else if let Ok(data) = serde_json::from_str::<B>(json_data) {
        println!("{:?}", data);
    }
}

Playground

It always succed on A, but I want it to fail because it has extra data so that it falls to B (where it matches exaclty). This is just an example of the problem I am having.

Hers answered 2/3, 2020 at 12:42 Comment(0)
C
6

Serde has many attributes to configure this kind of behavior.

One of them is #[serde(deny_unknown_fields)] which does exactly that:

use serde::{Deserialize, Serialize};
use serde_json; // 1.0.47; // 1.0.104

#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct A {
    pub item_1: i32,
    pub item_2: i32,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct B {
    pub item_1: i32,
    pub item_2: i32,
    pub item_3: i32,
}

fn main() {
    let json_data = r#"{"item_1" : 10, "item_2" : 100, "item_3" : 1000}"#;
    if let Ok(data) = serde_json::from_str::<A>(json_data) {
        println!("{:?}", data);
    } else if let Ok(data) = serde_json::from_str::<B>(json_data) {
        println!("{:?}", data);
    }
}

outputs:

B { item_1: 10, item_2: 100, item_3: 1000 }

(Permalink to the playground)

Coppery answered 2/3, 2020 at 12:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.