简体   繁体   中英

Serde Deserialize into one of multiple structs?

Is there a nice way to tentatively deserialize a JSON into different structs? Couldn't find anything in the docs and unfortunately the structs have "tag" to differentiate as in How to conditionally deserialize JSON to two different variants of an enum?

So far my approach has been like this:

use aws_lambda_events::event::{
    firehose::KinesisFirehoseEvent, kinesis::KinesisEvent,
    kinesis_analytics::KinesisAnalyticsOutputDeliveryEvent,
};
use lambda::{lambda, Context};
use serde_json::Value;

type Error = Box<dyn std::error::Error + Send + Sync + 'static>;
enum MultipleKinesisEvent {
    KinesisEvent(KinesisEvent),
    KinesisFirehoseEvent(KinesisFirehoseEvent),
    KinesisAnalyticsOutputDeliveryEvent(KinesisAnalyticsOutputDeliveryEvent),
    None,
}

#[lambda]
#[tokio::main]
async fn main(event: Value, _: Context) -> Result<String, Error> {
    let multi_kinesis_event = if let Ok(e) = serde_json::from_value::<KinesisEvent>(event.clone()) {
        MultipleKinesisEvent::KinesisEvent(e)
    } else if let Ok(e) = serde_json::from_value::<KinesisFirehoseEvent>(event.clone()) {
        MultipleKinesisEvent::KinesisFirehoseEvent(e)
    } else if let Ok(e) = serde_json::from_value::<KinesisAnalyticsOutputDeliveryEvent>(event) {
        MultipleKinesisEvent::KinesisAnalyticsOutputDeliveryEvent(e)
    } else {
        MultipleKinesisEvent::None
    };

    // code below is just sample

    let s = match multi_kinesis_event {
        MultipleKinesisEvent::KinesisEvent(_) => "Kinesis Data Stream!",
        MultipleKinesisEvent::KinesisFirehoseEvent(_) => "Kinesis Firehose!",
        MultipleKinesisEvent::KinesisAnalyticsOutputDeliveryEvent(_) => "Kinesis Analytics!",
        MultipleKinesisEvent::None => "Not Kinesis!",
    };
    Ok(s.to_owned())
}

You should use the #untagged option.

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]
struct KinesisFirehoseEvent {
    x: i32,
    y: i32
}

#[derive(Serialize, Deserialize, Debug)]
struct KinesisEvent(i32);

#[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)]
enum MultipleKinesisEvent {
    KinesisEvent(KinesisEvent),
    KinesisFirehoseEvent(KinesisFirehoseEvent),
    None,
}

fn main() {
    let event = MultipleKinesisEvent::KinesisFirehoseEvent(KinesisFirehoseEvent { x: 1, y: 2 });

    // Convert the Event to a JSON string.
    let serialized = serde_json::to_string(&event).unwrap();

    // Prints serialized = {"x":1,"y":2}
    println!("serialized = {}", serialized);

    // Convert the JSON string back to a MultipleKinesisEvent.
    // Since it is untagged 
    let deserialized: MultipleKinesisEvent = serde_json::from_str(&serialized).unwrap();

    // Prints deserialized = KinesisFirehoseEvent(KinesisFirehoseEvent { x: 1, y: 2 })
    println!("deserialized = {:?}", deserialized);
}

See in playground

Docs for: Untagged

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM