简体   繁体   中英

How do I use Serde to deserialize malformed JSON with True/False?

How can I deserialize the following malformed JSON using Rust's serde :

{
  "value": True
}

Using this answer , I tried the following solution:

#[macro_use]
extern crate serde_derive; // 1.0.66
extern crate serde; // 1.0.66
extern crate serde_json; // 1.0.21


use serde::de;
use std::fmt;

#[derive(Debug, PartialEq, Deserialize)]
pub struct Foo {
    #[serde(deserialize_with = "deserialize_capitalized_bool")]
    pub bar: bool,
}

fn deserialize_capitalized_bool<'de, D>(
    deserializer: D,
) -> Result<bool, D::Error>
where
    D: de::Deserializer<'de>,
{
    struct CapitalizedBoolVisitor;

    impl<'de> de::Visitor<'de> for CapitalizedBoolVisitor {
        type Value = bool;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a True or False string")
        }

        fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
        where
            E: de::Error,
        {
            if v == &['T' as u8, 'r' as u8, 'e' as u8] {
                Ok(true)
            } else if v
                == &['F' as u8, 'a' as u8, 'l' as u8, 's' as u8, 'e' as u8]
            {
                Ok(false)
            } else {
                unimplemented!();
            }
        }
    }

    deserializer.deserialize_any(CapitalizedBoolVisitor)
}

fn main() {
    let json = r#"{
        "bar": True
    }"#;

    let foo: Foo = serde_json::from_str(json).unwrap();

    let expected = Foo {
        bar: true
    };
    assert_eq!(foo, expected);
}

runnable on the playground

The problem, as far as I can tell, is that the input is not recognized as any correct type, so none of the visitor APIs work here.

UPDATE (2020-02-05) :

Apparently this is not possible to solve with serde_json (one way would be to use a custom data format or to fork serde_json to add this functionality, as serde_json does not deal with invalid input, see the maintainer's answer ).

A hacky solution, for anyone else having similar issues, is to replace the True and False instances in the raw response string to true and false . This is definitely not perfect, since if a string contains True or False , those would be replaced also, but it is perhaps an acceptable solution for specific use cases.

This is not valid JSON, so you can't use serde_json to deserialize it.

Boolean constants in JSON are true and false , in lower-case.

In general you can only deserialize input with a particular library if the input is in the data format that the library is for.

So for examples, if your input is not JSON, CBOR, MessagePack then you can't use serde_json, serde_cbor, or serde_messagepack to deserialize it.

The input you show appears to be YAML so you could try serde_yaml.

fn main() {
    let input = r#" {
                      "value": True
                    } "#;
    println!("{:#?}", serde_yaml::from_str::<serde_yaml::Value>(input).unwrap());
}

In other words the fact that data is invalid JSON tells you what library not to use — serde_json. To find the right library it's more useful to find a format that the data is valid in.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM