Need help with #[serde(deserialize_with)]


#1

Ok so straight to the point, i’m working with some broken json data.

{
    data: "stringified json here"
}

one of the fields is a stringified json. i need to tell serde to deserialize the field as a struct and not a string.
the docs say i can achieve this with the #[serde(deserialize_with)] attribute, but i’m ashamed to say i can’t figure it out.

#[derive(Serialize, Deserialize)]
struct Data {
    #[serde(deserialize_with = "deserialize_data")]
    data: ActualData
}

fn deserialize_data<'de, D>(data: D) -> Result<ActualData, D::Error>
where
	D: Deserializer<'de>,
{
  // i have no idea how i transform data: String to ActualData
}


#2

@seunlanlege In the body of deserialize_data you could use serde_json to deserialize the data within the stringified field. The Deserialize API can be tricky to hold, but following the docs on implementing Deserialize manually, you could do something like this:

#[derive(Debug, Deserialize)]
struct Data {
    #[serde(deserialize_with = "deserialize_json_string")]
    data: ActualData,
}

#[derive(Debug, Deserialize)]
struct ActualData {
    a: i32,
    b: String,
}

fn deserialize_json_string<'de, D>(deserializer: D) -> Result<ActualData, D::Error>
where
    D: de::Deserializer<'de>,
{
    // define a visitor that deserializes
    // `ActualData` encoded as json within a string
    struct JsonStringVisitor;

    impl<'de> de::Visitor<'de> for JsonStringVisitor {
        type Value = ActualData;
    
        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a string containing json data")
        }
    
        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
        where
            E: de::Error,
        {
            // unfortunately we lose some typed information
            // from errors deserializing the json string
            serde_json::from_str(v).map_err(E::custom)
        }
    }
    
    // use our visitor to deserialize an `ActualValue`
    deserializer.deserialize_any(JsonStringVisitor)
}

Here’s a runnable example.


#3

Thanks a lot for this :raised_hands:


#4

No problem! :smiley: I always keep the docs for serde close by for cases like this where you need to work with Serializers or Deserializers directly. Real data can be real messy.