Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#[serde(default = "...")] does not work on flatten-ed fields. #1879

Open
BertalanD opened this issue Aug 18, 2020 · 3 comments
Open

#[serde(default = "...")] does not work on flatten-ed fields. #1879

BertalanD opened this issue Aug 18, 2020 · 3 comments

Comments

@BertalanD
Copy link

I have a struct A that – along with other fields – contains a flattened B struct and a collection of B structs. I would like B's missing fields to take up a different default value if they are in the flattened field.

The problem

No matter what default attribute I set on the flatten-ed field, it will fall back to its type's default implementation.

For flattened structs, it would mean more sense that default applies to each field separately, as it's a way more common use case than wanting to fall back to the struct's Default implementation unless all of its fields are missing. But I am not even sure if that's how it's currently behaving.

Minimal example

These are my data structures:

#[derive(Serialize, Deserialize)]
#[serde(default)]
struct A {
    zero: usize,
    #[serde(flatten, default = "B::default_if_flattened")]
    b: B,
    c: Vec<B>,
}

impl Default for A {
    fn default() -> Self {
        A {
            zero: 0,
            b: B::default_if_flattened(),
            three: Vec::new(),
        }
    }
}

#[derive(Serialize, Deserialize)]
#[serde(default)]
struct B {
    one: Option<usize>,
    two: Option<String>
}

impl Default for B {
    fn default() -> Self {
        B {
            one: None,
            two: None
        }
    }
}

impl B {
    fn default_if_flattened() -> Self {
        B {
            one: Some(1),
            two: Some(String::from("two"))
        }
    }
}

And I want to deserialize the following TOML file:

zero = 0
two = "two"

three = [ { } ]

Expected results when deserialized into a value: A:

value.b.one == Some(1)
value.three[0].one == None

Here is the same thing in the Rust Playground (currently panics.)

@maxcountryman
Copy link

I seem to be running into the same issue with #[serde(default, flatten)] where my field type impls Default.

Any workarounds for this?

@ByteNacked
Copy link

Same thing, flatten doesn't work with default, nor with manual default trait impl nor with derive(default).

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct User {
    #[serde(flatten, default)]
    contact: Contact,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
struct Contact {
    email: String,
    phone: String,
}

fn main() {
    let json = r#"{
        "email": "[email protected]"
    }"#;

    let user: User = serde_json::from_str(json).unwrap();
    let expected_user = User { contact: Contact { email: "[email protected]".to_string(), phone: "".to_string() } };
    assert_eq!(user, expected_user);
}

panics with:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error("missing field `phone`", line: 3, column: 5)', src/main.rs:20:49

playground link

@Mingun
Copy link
Contributor

Mingun commented Aug 11, 2023

This is duplicate of #1626

flavio added a commit to flavio/kube that referenced this issue Jan 25, 2024
…tion

The `serde` crate has a bug that prevents the proper deserialization of
attributes that are using the `flatten` and `default` directives.
See [1] and [2].

This bug affects the freshly introduced `ObjectList.types` attribute.
It's not possible to deserialize an `ObjectList` that is missing the
`apiVersion` and/or the `kind` values.

This commit introduces a custom deserializer for the `types` attribute
of `ObjectList`.

On top of handling the deserialization case, the custom deserializer
provides better default values compared to the ones of the stock
`TypeMeta`.
The `TypeMeta` struct has empty strings as default values. However, in the
context of `ObjectList`, proper default values should be `v1` and `List`
instead.

[1] serde-rs/serde#1626
[2] serde-rs/serde#1879

Signed-off-by: Flavio Castelli <[email protected]>
clux pushed a commit to kube-rs/kube that referenced this issue Jan 26, 2024
* fix: ObjectList handle missing apiVersion and kind during deserialization

The `serde` crate has a bug that prevents the proper deserialization of
attributes that are using the `flatten` and `default` directives.
See [1] and [2].

This bug affects the freshly introduced `ObjectList.types` attribute.
It's not possible to deserialize an `ObjectList` that is missing the
`apiVersion` and/or the `kind` values.

This commit introduces a custom deserializer for the `types` attribute
of `ObjectList`.

On top of handling the deserialization case, the custom deserializer
provides better default values compared to the ones of the stock
`TypeMeta`.
The `TypeMeta` struct has empty strings as default values. However, in the
context of `ObjectList`, proper default values should be `v1` and `List`
instead.

[1] serde-rs/serde#1626
[2] serde-rs/serde#1879

Signed-off-by: Flavio Castelli <[email protected]>

* ObjectList: derive the `Clone` trait

Ensure `ObjectList` derive the `Clone` trait.

Signed-off-by: Flavio Castelli <[email protected]>

* chore: fix rustfmt warning

Signed-off-by: Flavio Castelli <[email protected]>

---------

Signed-off-by: Flavio Castelli <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

4 participants