Rust/Serde: serialize external struct to json camelcase
Asked Answered
A

1

6

I am working on some code that takes a struct returned by an external library, serializes it to json, and serializes the json to protobuf using pbjson. The external library uses serde and implements Serialize, but the json that is returned is snake case. The problem is that pbjson is expecting the json to be camelcase.

How can I get a camelcase version of the serde json object? (ie configure the external library to use something like #[serde(rename_all = "camelCase")] or to convert the json keys to camelcase?)

Note: I am working with many remote structs that in total add up to almost 2k lines of code. I would like to avoid recreating these types locally if possible.

Apatite answered 19/9, 2022 at 18:58 Comment(2)
serde.rs/remote-derive.htmlKassie
@Kassie I've seen that, but was hoping to not have to go that route since Serialize and Deserialize have already been implemented in the external crate.Apatite
E
3

If I understand correctly, you want something like this? Basically you just need to turn the foreign items into items of your own type and then serialize those.

// foreign struct
#[derive(Serialize, Deserialize)]
struct Foreign {
    the_first_field: u32,
    the_second_field: String,
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct Mine {
    the_first_field: u32,
    the_second_field: String,
}

impl From<Foreign> for Mine {
    fn from(
        Foreign {
            the_first_field,
            the_second_field,
        }: Foreign,
    ) -> Self {
        Self {
            the_first_field,
            the_second_field,
        }
    }
}

fn main() {
    // only used to construct the foreign items
    let in_json = r#"[{"the_first_field": 1, "the_second_field": "second"}]"#;

    let foreign_items = serde_json::from_str::<Vec<Foreign>>(in_json).unwrap();

    let mine_items = foreign_items.into_iter().map(Mine::from).collect::<Vec<_>>();
    let out_json = serde_json::to_string(&mine_items).unwrap();

    println!("{}", out_json);  // [{"theFirstField":1,"theSecondField":"second"}]
}
Eubank answered 19/9, 2022 at 19:43 Comment(2)
This will work, but will also require a lot of work. I updated the question to explain why. I will hold off on accepting for now in case there is a better solution. I appreciate you taking the time to come up with this solution :)Apatite
In that case you can serialize to JSON, deserialize to a HashMap, manually titlecase the keys yourself (using the heck crate), and serialize back. Poor performance, but it'll work.Eubank

© 2022 - 2024 — McMap. All rights reserved.