Serde rename field attribute only for Serialize or Deserialize
deankarn opened this issue · 3 comments
Hi, first off Serde is amazing!
I came across a situation where I needed to rename a field for Deserialization and so came across the rename file attribute; the only issue is that I do not want to rename the Serialize, but use the rust name.
The situation I am using this in is accepting input from a legacy API and so want to remap the old names, however when serializing the same data to be stored/used in a new piece of code I didn't see a way to rename just Serialize or Deserialize and not both;
Is this possible? or could an option be added like rename_serialize
& rename_deserialize
?
it's possible I have missed this functionlity in the docs, thanks for any help :)
The rename attribute supports passing distinct serialize and deserialize renames. I was not able to find documentation of this either so I filed serde-rs/serde-rs.github.io#77 to follow up.
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
#[derive(Serialize, Deserialize)]
struct Joeybloggs {
#[serde(rename(deserialize = "old", serialize = "new"))]
field: i32,
}
fn main() {
let j = serde_json::from_str::<Joeybloggs>("{\"old\":0}").unwrap();
println!("{}", serde_json::to_string(&j).unwrap());
}
Awesome! @dtolnay thank you for the quick response! seems like your everywhere! ;)
Hi, I am a bit confused about the backwards compatibility. Won't the example above crash if we try to serialize then re-load a freshly created struct?
For example, if I add something like this:
let fresh_version = Joeybloggs { field: 1234i32 };
let serialized = serde_json::to_string::<Joeybloggs>(&fresh_version).unwrap();
println!("{:?}", serialized);
let reconstructed = serde_json::from_str::<Joeybloggs>(&serialized);
println!("Reconstructed: {:?}", reconstructed);
I can serialize it just fine, but then if I attempt to reconstruct the struct I just created, I get this error:
Reconstructed: Err(Error("missing field `old`", line: 1, column: 12))
If I just pass 'old' to both 'deserialize' and 'serialize', then the code works but it also means that any new serialized structs will just use the old-school API forever.
Solution: I found out that I can instead use alias
to get what I want. Here is the full code which is backwards compatible with structs containing 'old', but uses 'field' for current and future cases.
extern crate serde;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
struct Joeybloggs {
#[serde(alias = "old")]
field: i32,
}
fn main() {
let j = serde_json::from_str::<Joeybloggs>("{\"old\":0}").unwrap();
println!("{}", serde_json::to_string(&j).unwrap());
let fresh_version = Joeybloggs { field: 1234i32 };
let serialized = serde_json::to_string::<Joeybloggs>(&fresh_version).unwrap();
println!("{:?}", serialized);
let reconstructed = serde_json::from_str::<Joeybloggs>(&serialized);
println!("Reconstructed: {:?}", reconstructed);
}
#[cfg(test)]
mod tests {}