2017-09-27 58 views
1

我目前正在爲golang中的博客開發JSON API,並且遇到試圖處理博客帖子的序列化和反序列化的障礙。我希望我的帖子包含可能包含許多內容(如正常段落,圖片,引號等)的帖子部分數組。我使用蒙戈存儲(與驚人的mgo library),我要保存這樣的帖子:Go中的接口的自定義JSON序列化和反序列化

{ 
    "title": "Blog post", 
    "sections": [ 
    { 
     "type": "text", 
     "content": { "en": "English content", "de": "Deutscher Inhalt" } 
    }, 
    { 
     "type": "image", 
     "content": "https://dummyimage.com/100x100" 
    }, 
    ...more sections 
    ], 
    ...other fields 
} 

我已經嘗試了幾種解決方案中去實現這一點,並沒有真的似乎是「正確的方法」來做到這一點:

  1. 不關心內容

這似乎是顯而易見的解決方案,只是用一個簡單的結構:

type PostSection struct{ 
    Type string 
    Content interface{} 
} 

這樣,我可以通過任何前端POSTS並保存它。但是,操縱數據或驗證數據變得不可能,所以這不是一個好的解決方案。

  • 使用自定義接口系列化
  • 我發現this article有關golang串行接口。這似乎在第一個偉大的,因爲我有一個這樣的接口:

    type PostSection interface{ 
        Type() string 
        Content() interface{} 
    } 
    

    ,然後實現所有類型如下:

    type PostImage string 
    
    func (p *PostImage) Type() string { 
        return "image" 
    } 
    
    func (p *PostImage) Content() interface{} { 
        return p 
    } 
    

    理想情況下,這將一直是,貫徹MarshalJSON後和UnmarshalJSON所有我的類型,它直接在PostSection對象上使用json.Marshal時工作正常。

    然而,序列化或反序列化含有PostSection秒的陣列的整個Post對象時,我的自定義代碼只是被忽略並且PostSections只想被視爲串行化時底層對象(在實施例中stringmap[string]string),或者在反序列化時導致空對象。

    對於整個郵政結構

    整個Post對象所以,我目前使用,但希望改變溶液是自定義序列

  • 編寫自定義序列。這導致超級醜陋的代碼,因爲我只真正需要自定義代碼的單一領域,所以我經過休息,使反序列化類似於此:

    p.ID = decoded.ID 
    p.Author = decoded.Author 
    p.Title = decoded.Title 
    p.Intro = decoded.Intro 
    p.Slug = decoded.Slug 
    p.TitleImage = decoded.TitleImage 
    p.Images = decoded.Images 
    ...more fields... 
    

    ,然後,像切片解碼這樣的:

    sections := make([]PostSection, len(decoded.Sections)) 
    for i, s := range decoded.Sections { 
        if s["type"] == "text" { 
         content := s["content"].(map[string]interface{}) 
         langs := make(PostText, len(content)) 
         for lang, langContent := range content { 
          langString := langContent.(string) 
          langs[lang] = langString 
         } 
         sections[i] = &langs 
        } else if s["type"] == "image" { 
         content := s["content"].(string) 
         contentString := PostImage(content) 
         sections[i] = &contentString 
        } 
    } 
    
    p.Sections = sections 
    

    這是一大堆的代碼,我將不得不使用每次我想包括以另一種形式在其他地方(例如在通訊)PostSections時間,它不覺得自己是地道的Go代碼通過一次遠射。此外,沒有錯誤處理格式錯誤的部分 - 他們只是造成這樣的恐慌。

    有沒有一個乾淨的解決這個問題?

  • +1

    #2,'當對包含PostSections數組的整個Post對象進行序列化或反序列化時,我的自定義代碼沒有被使用,並且我會得到錯誤。什麼錯誤?你是否爲Post對象本身實現了'MarshalJSON'和'UnmarshalJSON'? – RayfenWindspear

    +0

    對不起,但似乎我記得那是錯的。我只是試了一遍,錯誤只出現在試圖從mgo反序列化時,因爲它找不到PostSection接口的SetBSON方法。至於你的第二個問題,我在#3中談論這個問題。 – happens

    回答

    1

    要避免爲整個Post編寫UnmarshalJSON,您可以將PostSection包裝爲具體類型並使其實現Unmarshaler接口。

    type Post struct { 
        ID   int 
        Author  string 
        Title  string 
        Intro  string 
        Slug  string 
        TitleImage string 
        Images  []string 
    
        Sections []*PostSection 
    } 
    
    type SectionContent interface { 
        Type() string 
        Content() interface{} 
    } 
    
    type PostSection struct { 
        Content SectionContent 
    } 
    
    func (s *PostSection) UnmarshalJSON(data []byte) error { 
        // ... 
        return nil 
    } 
    
    +0

    這很好,非常感謝!現在感覺很明顯,呃... – happens

    相關問題