How to deserialize a JSON file which contains null values using Serde?
A deserialization error occurs because the struct definition is incompatible with the incoming objects: the color
field can also be null
, as well as a string, yet giving this field the type String
forces your program to always expect a string. This is the default behaviour, which makes sense. Be reminded that String
(or other containers such as Box
) are not "nullable" in Rust. As for a null
value not triggering the default value instead, that is just how Serde works: if the object field wasn't there, it would work because you have added the default field attribute. On the other hand, a field "color" with the value null
is not equivalent to no field at all.
One way to solve this is to adjust our application's specification to accept null | string
, as specified by @user25064's answer:
#[derive(Serialize, Deserialize, Debug, Clone)]pub struct Element { color: Option<String>,}
Playground with minimal example
Another way is to write our own deserialization routine for the field, which will accept null
and turn it to something else of type String
. This can be done with the attribute #[serde(deserialize_with=...)]
.
#[derive(Serialize, Deserialize, Debug, Clone)]pub struct Element { #[serde(deserialize_with="parse_color")] color: String,}fn parse_color<'de, D>(d: D) -> Result<String, D::Error> where D: Deserializer<'de> { Deserialize::deserialize(d) .map(|x: Option<_>| { x.unwrap_or("black".to_string()) })}
See also:
Based on code from here, when one needs default values to be deserialized if null
is present.
// Omitting other derives, for brevity #[derive(Deserialize)]struct Foo { #[serde(deserialize_with = "deserialize_null_default")] value: String, }fn deserialize_null_default<'de, D, T>(deserializer: D) -> Result<T, D::Error>where T: Default + Deserialize<'de>, D: Deserializer<'de>,{ let opt = Option::deserialize(deserializer)?; Ok(opt.unwrap_or_default())}
playground link with full example. This also works for Vec
and HashMap
.