将JSON字符串或字符串数组反序列化为Vec

Arnavion

我正在编写一个与JSON Web API接口的板条箱。一个端点通常返回形式的响应{ "key": ["value1", "value2"] },但有时该键只有一个值,并且端点返回{ "key": "value" }而不是{ "key": ["value"] }

我想为此编写一些通用的东西,#[serde(deserialize_with)]例如:

#[derive(Deserialize)]
struct SomeStruct {
    #[serde(deserialize_with = "deserialize_string_or_seq_string")]
    field1: Vec<SomeStringNewType>,

    #[serde(deserialize_with = "deserialize_string_or_seq_string")]
    field2: Vec<SomeTypeWithCustomDeserializeFromStr>,
}

#[derive(Deserialize)]
struct SomeStringNewType(String);

struct SomeTypeWithCustomDeserializeFromStr(String);
impl ::serde::de::Deserialize for SomeTypeWithCustomDeserializeFromStr {
    // Some custom implementation here
}

我该如何写deserialize_string_or_seq_string才能做到这一点?

Arnavion

此解决方案适用于Serde 1.0。

我发现的方法还要求我编写一个自定义反序列化器,因为我需要一个可以调用的方法visitor.visit_newtype_struct来尝试对新类型进行反序列化,而且似乎没有内置于Serde中的这样做。(我期待类似的ValueDeserializer一系列类型。)

下面是一个独立的示例。SomeStruct正确反序列化的两个输入,一个地方的值是JSON字符串数组,另在那里他们只是字符串。

#[macro_use]
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

fn main() {
    #[derive(Debug, Deserialize)]
    struct SomeStringNewType(String);

    #[derive(Debug)]
    struct SomeTypeWithCustomDeserializeFromStr(String);
    impl<'de> ::serde::Deserialize<'de> for SomeTypeWithCustomDeserializeFromStr {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: ::serde::Deserializer<'de> {
            struct Visitor;

            impl<'de> ::serde::de::Visitor<'de> for Visitor {
                type Value = SomeTypeWithCustomDeserializeFromStr;

                fn expecting(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                    write!(f, "a string")
                }

                fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> where E: ::serde::de::Error {
                    Ok(SomeTypeWithCustomDeserializeFromStr(v.to_string() + " custom"))
                }
            }

            deserializer.deserialize_any(Visitor)
        }
    }

    #[derive(Debug, Deserialize)]
    struct SomeStruct {
        #[serde(deserialize_with = "deserialize_string_or_seq_string")]
        field1: Vec<SomeStringNewType>,

        #[serde(deserialize_with = "deserialize_string_or_seq_string")]
        field2: Vec<SomeTypeWithCustomDeserializeFromStr>,
    }

    let x: SomeStruct = ::serde_json::from_str(r#"{ "field1": ["a"], "field2": ["b"] }"#).unwrap();
    println!("{:?}", x);
    assert_eq!(x.field1[0].0, "a");
    assert_eq!(x.field2[0].0, "b custom");

    let x: SomeStruct = ::serde_json::from_str(r#"{ "field1": "c", "field2": "d" }"#).unwrap();
    println!("{:?}", x);
    assert_eq!(x.field1[0].0, "c");
    assert_eq!(x.field2[0].0, "d custom");
}

/// Deserializes a string or a sequence of strings into a vector of the target type.
pub fn deserialize_string_or_seq_string<'de, T, D>(deserializer: D) -> Result<Vec<T>, D::Error>
    where T: ::serde::Deserialize<'de>, D: ::serde::Deserializer<'de> {

    struct Visitor<T>(::std::marker::PhantomData<T>);

    impl<'de, T> ::serde::de::Visitor<'de> for Visitor<T>
        where T: ::serde::Deserialize<'de> {

        type Value = Vec<T>;

        fn expecting(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
            write!(f, "a string or sequence of strings")
        }

        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where E: ::serde::de::Error {

            let value = {
                // Try parsing as a newtype
                let deserializer = StringNewTypeStructDeserializer(v, ::std::marker::PhantomData);
                ::serde::Deserialize::deserialize(deserializer)
            }.or_else(|_: E| {
                // Try parsing as a str
                let deserializer = ::serde::de::IntoDeserializer::into_deserializer(v);
                ::serde::Deserialize::deserialize(deserializer)
            })?;
            Ok(vec![value])
        }

        fn visit_seq<A>(self, visitor: A) -> Result<Self::Value, A::Error>
            where A: ::serde::de::SeqAccess<'de> {

            ::serde::Deserialize::deserialize(::serde::de::value::SeqAccessDeserializer::new(visitor))
        }
    }

    deserializer.deserialize_any(Visitor(::std::marker::PhantomData))
}

// Tries to deserialize the given string as a newtype
struct StringNewTypeStructDeserializer<'a, E>(&'a str, ::std::marker::PhantomData<E>);

impl<'de, 'a, E> ::serde::Deserializer<'de> for StringNewTypeStructDeserializer<'a, E> where E: ::serde::de::Error {
    type Error = E;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> where V: ::serde::de::Visitor<'de> {
        visitor.visit_newtype_struct(self)
    }

    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error> where V: ::serde::de::Visitor<'de> {
        // Called by newtype visitor
        visitor.visit_str(self.0)
    }

    forward_to_deserialize_any! {
        bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str bytes
        byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map
        struct enum identifier ignored_any
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

将字符串数组反序列化为csv

将请求字符串反序列化为数组

将JSON字符串反序列化为Class

使用JSON.NET将JSON数组反序列化为字符串数组

将JSON数组反序列化为字符串数组

防止Json.NET将字符串数组反序列化为键值对数组

将JSON单个字符串反序列化为数组

将一属性对象的JSON数组反序列化为字符串集合

将字符串数组序列化为json

将具有多个元素的 JSON 字段从字符串反序列化为 Vec<u8>s 的 Vec

将字符串反序列化为双倍

将字符串反序列化为Google TokenResponse

将XML字符串反序列化为类

将Mongodb字符串反序列化为对象

将具有特殊字符的JSON反序列化为字符串

将JSON反序列化为C#对象以将嵌套数组显示为网格中的字符串

Jackson:将空字符串反序列化为空字符串

Jackson:将字符串数组反序列化为List <T>

如何将字符串数组反序列化为class []?

C#Json.net将嵌套的json反序列化为字符串

将Json Schema反序列化为Json字符串或对象

如何将逗号分隔的JSON字符串反序列化为单独字符串的向量?

将多个不同的键/值 JSon 数组/字符串反序列化为 C# 中相同类的集合

将json字符串反序列化为通用类型的列表

避免gson将json字符串反序列化为LinkedHashMap类成员

无法将 Json 文件反序列化为带有字符串“key”的 KeyValuePair 列表

将JSON字符串反序列化为Java Object

将Json字符串反序列化为对象Java

F#将JSON反序列化为字符串或节点