27

The serde_json::to_string() function will generate a string which may include null for an Option<T>, or 0 for a u32. This makes the output larger, so I want to ignore these sorts of values.

I want to simplify the JSON string output of the following structure:

use serde_derive::Serialize; // 1.0.82

#[derive(Serialize)]
pub struct WeightWithOptionGroup {
    pub group: Option<String>,
    pub proportion: u32,
}

When group is None and proportion is 0, the JSON string should be "{}"

Thanks for the answerHow do I change Serde's default implementation to return an empty object instead of null?, it can resolve Optionproblem, but for 0 there is none solution.

llxxbb
  • 1,241
  • 1
  • 10
  • 16
  • Duplicate of [How do I change Serde's default implementation to return an empty object instead of null?](https://stackoverflow.com/q/46993079/155423) – Shepmaster Dec 31 '18 at 14:23
  • 3
    Possible duplicate of [How do I change Serde's default implementation to return an empty object instead of null?](https://stackoverflow.com/questions/46993079/how-do-i-change-serdes-default-implementation-to-return-an-empty-object-instead) – Stargateur Dec 31 '18 at 14:28
  • it can resolve `Option` problem, but for 0 there is none solution. – llxxbb Jan 01 '19 at 08:55

3 Answers3

57

The link Skip serializing field give me the answer.

And the fixed code:

#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Ord, PartialOrd, Eq)]
pub struct WeightWithOptionGroup {
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    pub group: Option<String>,
    #[serde(skip_serializing_if = "is_zero")]
    #[serde(default)]
    pub proportion: u32,
}

/// This is only used for serialize
#[allow(clippy::trivially_copy_pass_by_ref)]
fn is_zero(num: &u32) -> bool {
    *num == 0
}
llxxbb
  • 1,241
  • 1
  • 10
  • 16
3

There's a couple of ways you could do this:

  • Mark each of the fields with a skip_serialising_if attribute to say when to skip them. This is much easier, but you'll have to remember to do it for every field.
  • Write your own Serde serialiser that does this custom JSON form. This is more work, but shouldn't be too bad, especially given you can still use the stock JSON deserialiser.
Tom Parker-Shemilt
  • 1,679
  • 15
  • 26
0

For those searching how to skip serialization for some enum entries you can do this

#[derive(Serialize, Deserialize)]
enum Metadata {
  App,             // want this serialized
  Ebook,           // want this serialized
  Empty            // dont want this serialized
}

#[derive(Serialize, Deserialize)]
struct Request<'a> {
    request_id: &'a str,
    item_type: ItemType,
    #[serde(skip_serializing_if = "Metadata::is_empty")]
    metadata: Metadata,
}

impl Metadata {
    fn is_empty(&self) -> bool {
        match self {
            Metadata::Empty => true,
            _ => false,
        }
    }
}
T0xicCode
  • 4,583
  • 2
  • 37
  • 50
thiagoh
  • 7,098
  • 8
  • 51
  • 77