Go

时间:2017-09-27 18:05:56

标签: json go serialization

我目前正在golang中为博客开发JSON API,并且我遇到了试图处理博客帖子的序列化和反序列化的障碍。我希望我的帖子包含一系​​列帖子部分,这些部分可能是很多东西(例如普通段落,图像,引号等)。我使用Mongo进行存储(使用惊人的mgo library)并且我想保存这样的帖子:

{
  "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. 不关心内容
  2. 这似乎是一个明显的解决方案,只需使用一个简单的结构:

    type PostSection struct{
      Type    string
      Content interface{}
    }
    

    这样,我可以通过任何前端POSTS并保存它。但是,操纵数据或验证数据变得不可能,因此它不是一个好的解决方案。

    1. 使用自定义界面序列化
    2. 我发现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
      }
      

      最理想的情况是,在为我的所有类型实现MarshalJSONUnmarshalJSON之后,直接在PostSection对象上使用json.Marshal时,它工作正常。

      但是,在序列化或反序列化包含PostSection数组的整个Post对象时,我的自定义代码被忽略,PostSections只会被视为底层对象(string或{序列化时的示例中的{1}},或者在反序列化时导致空对象。

      1. 为整个Post结构编写自定义序列化
      2. 因此,我目前正在使用但希望更改的解决方案是整个Post对象的自定义序列化。这导致了超级丑陋的代码,因为我只需要为单个字段定制代码,因此我会通过其余字段,使反序列化看起来与此类似:

        map[string]string

        然后解码这样的部分:

        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...
        

        这是我每次想在其他地方以其他形式包含PostSections时必须使用的大量代码(例如在时事通讯中),并且它并不像惯用的代码那样远射。此外,对于格式错误的部分没有错误处理 - 它们只会引起这样的恐慌。

        这个问题有一个干净的解决方案吗?

1 个答案:

答案 0 :(得分:2)

为避免为整个UnmarshalJSON编写Post,您可以将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
}