Serde: Ability to use default value even if set to null

Created on 23 Nov 2017  路  4Comments  路  Source: serde-rs/serde

default does not treat a field being set to null equal to the field being emitted. More concretely, the following code will panic in the line where it attempts to deserialize request_c:

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

#[derive(Serialize, Deserialize, Debug)]
struct Request {
    #[serde(default = "Priority::lowest")]
    priority: Priority,
}

#[derive(Serialize, Deserialize, Debug)]
enum Priority { ExtraHigh, High, Normal, Low, ExtraLow }
impl Priority {
    fn lowest() -> Self { Priority::ExtraLow }
}

fn main() {

    let request_a: Request = serde_json::from_str(r"{}").unwrap();
    println!("{:?}", request_a);

    let request_b: Request = serde_json::from_str(r#"{"priority": "High"}"#).unwrap();
    println!("{:?}", request_b);

    let request_c: Request = serde_json::from_str(r#"{"priority": null}"#).unwrap();
    //^~ PANIC: ErrorImpl { code: ExpectedSomeValue, line: 1, column: 14 }
    println!("{:?}", request_c);

}

The data I want to process sometimes has its field set, sometimes it is set to null, and sometimes it is omitted. I want to set a default for when it is null or omitted.

This doesn't need to be the default behaviour but having sth like #[serde(default_on_null)] would be really nice :). Thanks to @oli-obk suggesting that on IRC.

derive

All 4 comments

I am open to supporting this better. For now the current workaround would be a deserialize_with function that handles null.

use serde::{Deserialize, Deserializer};

#[derive(Serialize, Deserialize, Debug)]
struct Request {
    #[serde(default = "Priority::lowest", deserialize_with = "nullable_priority")]
    priority: Priority,
}

fn nullable_priority<'de, D>(deserializer: D) -> Result<Priority, D::Error>
    where D: Deserializer<'de>
{
    let opt = Option::deserialize(deserializer)?;
    Ok(opt.unwrap_or_else(Priority::lowest))
}

@dtolnay oh thanks. That's nice and small compared to the monster that I wrote :)...

A default_on_null function would be a reasonable addition to a Serde helper library such as serde-aux or serde_with. I am closing this issue because I don't think we need to introduce a new Serde attribute for this use case.

Hi! Thank you for an awesome serde :)

Sorry for writing to an old thread, just wanted to know why there's a need for a separate attribute? Couldn't default do the trick?

If I understand correctly, in the case of JSON deserializing #[serde(default)] struct from "{}" yields default value, while deserializing from "null" gives error:

invalid type: null, expected struct

Here's an example code
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=9cda0c82d5f144615db93666bee84d24

Is that an expected behaviour, or an inconsistency of serde/serde_json? I would expect {} and null both yield a default value.

Thanks in advance!

Was this page helpful?
0 / 5 - 0 ratings