This answer predates the extra requirements given as comments by the OP, but is left as-is as the extra requirements makes it a separate question.
To handle trailing commas
The input data provided in the question is not valid JSON, due to the existence of trailing commas before every closing bracket }
. If you must work with trailing commas, then the conventional serde_json
crate doesn't suit your needs, and you may want to replace all usages of serde_json
with crates supporting trailing commas like the json5
crate. The json5
provides an API that's similar to serde_json
, so the following answer is still valid.
To handle fields that can be of multiple types
Handling JSON fields with multiple possible value types can be done with an enum
that holds either a String
or a Vec<String>
, with the #[serde(untagged)]
attribute. See Enum representations from the official documentation of serde for details about the attribute.
Full example:
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
enum StringOrStringVec {
String(String),
Vec(Vec<String>)
}
#[derive(Debug, Serialize, Deserialize)]
struct MyObj {
keya: StringOrStringVec,
keyb: StringOrStringVec,
}
fn main() {
let input_json = r#"
{
"keya": "some string",
"keyb": ["some string", "some string"]
}
"#;
let my_obj: MyObj = serde_json::from_str(input_json).unwrap();
println!("{:?}", my_obj);
let input_json = r#"
{
"keya": ["some string", "some string"],
"keyb": "some string"
}
"#;
let my_obj: MyObj = serde_json::from_str(input_json).unwrap();
println!("{:?}", my_obj);
}
Example output:
MyObj { keya: String("some string"), keyb: Vec(["some string", "some string"]) }
MyObj { keya: Vec(["some string", "some string"]), keyb: String("some string") }
See it in action on Rust Playground