2016-12-14 131 views
2

我在寫一個與JSON Web API接口的箱子。一個端點通常返回的形式{ "key": ["value1", "value2"] }的反應,但有時也有隻有一個鍵值,並把端點返回的{ "key": "value" }代替{ "key": ["value"] }反序列化一個JSON字符串或字符串數​​組到一個Vec

我想寫這個東西一般是我能與#[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才能做到這一點?

回答

0

該解決方案適用於Serde 1.0。

我發現的方式也需要我編寫一個自定義的反序列化器,因爲我需要一個可以調用visitor.visit_newtype_struct來嘗試反序列化newtypes的方法,並且似乎沒有任何內置到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 
    } 
} 
2

如果你想反序列化一個字符串或到更一般的Vec<String>,而不是自定義類型的字符串列表,下面是SERDE 1.0簡單的解決方案:

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

use std::fmt; 
use std::marker::PhantomData; 

use serde::de; 
use serde::de::{Deserialize, Deserializer}; 

#[derive(Deserialize, Debug, Clone)] 
pub struct Parent { 
    #[serde(deserialize_with = "string_or_seq_string")] 
    pub strings: Vec<String>, 
} 

fn main() { 
    let list_of_strings: Parent = serde_json::from_str(r#"{ "strings": ["value1", "value2"] }"#).unwrap(); 
    println!("list of strings: {:?}", list_of_strings); 
    // Prints: 
    // list of strings: Parent { strings: ["value1", "value2"] } 

    let single_string: Parent = serde_json::from_str(r#"{ "strings": "value" }"#).unwrap(); 
    println!("single string: {:?}", single_string); 
    // Prints: 
    // single string: Parent { strings: ["value"] } 
} 

fn string_or_seq_string<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error> 
    where D: Deserializer<'de> 
{ 
    struct StringOrVec(PhantomData<Vec<String>>); 

    impl<'de> de::Visitor<'de> for StringOrVec { 
     type Value = Vec<String>; 

     fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 
      formatter.write_str("string or list of strings") 
     } 

     fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> 
      where E: de::Error 
     { 
      Ok(vec![value.to_owned()]) 
     } 

     fn visit_seq<S>(self, visitor: S) -> Result<Self::Value, S::Error> 
      where S: de::SeqAccess<'de> 
     { 
      Deserialize::deserialize(de::value::SeqAccessDeserializer::new(visitor)) 
     } 
    } 

    deserializer.deserialize_any(StringOrVec(PhantomData)) 
} 

這解決方案也適用0.9版本SERDE下有以下變化:

  • 刪除壽命
  • SeqAccess - >SeqVisitor
  • SeqAccessDeserializer - >SeqVisitorDeserializer
  • MapAccess - >MapVisitor
  • MapAccessDeserializer - >MapVisitorDeserializer
+0

這並不反序列化'SomeStringNewType(字符串)'或'SomeTypeWithCustomDeserializeFromStr(字符串)'作爲問題需要。 – Arnavion

+1

對不起 - 我的理解是'SomeStringNewType'是某種形式的解決方法,因爲你不能讓它與'String'一起工作。如果你不介意,我仍然會保留這個答案,因爲至少我遇到了這個問題,因爲我搜索了它的標題。我已經更新了答案,指出這是爲了想要一個簡單的'String'的一般形式。 – Pit

+1

是的,您的答案適用於用戶想要直接反序列化字符串的情況。沒有理由刪除它。 – Arnavion

相關問題