golang json序列化/反序列化递归数据模型

时间:2016-06-24 15:41:30

标签: json serialization go

让我说我有:

type IObject interface {
}

type Item struct {
    Description string
    Data        []byte
}

type FunctionX1 struct {
    Object IInclusionObject
}

type FunctionX2 struct {
    Object1 IInclusionObject
    Object2 IInclusionObject
}

我希望能够对模型进行序列化/反序列化,其中ItemFunctionX1 FunctionX2它们都实现IObject,它们可以任意指向对方深。

请注意,我不希望将FunctionX1{Item{"foo", []byte("bar")}}序列化为:

"object": {
    "Description": "foo"
    "Data": ...
}

而是:

"FunctionX1": {
    "item": { 
        "Description": "foo"
        "Data": ...
    }
}

我是否需要自己制作JSON编组器 - 我似乎无法使用现有的编组器。

如果我需要自己的相关问题。是否有JSON美化我可以流式传输有效但随机格式化的JSON并输出漂亮的版本(注意JSON可能非常大 - 我不想生成,解析生成格式化)。

1 个答案:

答案 0 :(得分:2)

使用Wrappers(struct或map)

您可以使用struct tags将结构的字段映射到JSON中的不同名称。因此,您可以将"Object"更改为"item"

type FunctionX1 struct {
    Object IInclusionObject `json:"item"`
}

但是,如果希望{J}文本中出现"FunctionX1",则仍需要包装器结构或映射。例如:

f := FunctionX1{Item{"foo", []byte("bar")}}

if data, err := json.Marshal(map[string]interface{}{"FunctionX1": f}); err != nil {
    panic(err)
} else {
    fmt.Println(string(data))
}

输出:

{"FunctionX1":{"item":{"Description":"foo","Data":"YmFy"}}}

或者使用包装器结构:

type Wrapper struct {
    FunctionX1 FunctionX1
}

f := FunctionX1{Item{"foo", []byte("bar")}}

if data, err := json.Marshal(Wrapper{f}); err != nil {
    panic(err)
} else {
    fmt.Println(string(data))
}

输出相同:

{"FunctionX1":{"item":{"Description":"foo","Data":"YmFy"}}}

如果你想要格式化的JSON,你可以使用json.MarshalIndent()进行编组:

if data, err := json.MarshalIndent(Wrapper{f}, "", "  "); err != nil {
    panic(err)
} else {
    fmt.Println(string(data))
}

输出:

{
  "FunctionX1": {
    "item": {
      "Description": "foo",
      "Data": "YmFy"
    }
  }
}

尝试Go Playground上的所有示例。

使用自定义封送

如果您不想使用包装器结构或地图,则需要使用自定义编组,但这很简单:

type FunctionX1 struct {
    Object IInclusionObject `json:"item"`
}

func (f FunctionX1) MarshalJSON() ([]byte, error) {
    type FunctionX1_ FunctionX1
    return json.Marshal(map[string]interface{}{"FunctionX1": FunctionX1_(f)})
}

有效地,我们将包装移到MarshalJSON()方法中,因此其他人编组FunctionX1的值不必。

测试它:

f := FunctionX1{Item{"foo", []byte("bar")}}

if data, err := json.Marshal(f); err != nil {
    panic(err)
} else {
    fmt.Println(string(data))
}

if data, err := json.MarshalIndent(f, "", "  "); err != nil {
    panic(err)
} else {
    fmt.Println(string(data))
}

请注意,FunctionX1_内的新MarshalJSON()类型是为了避免无限的"递归"。

输出:

{"FunctionX1":{"item":{"Description":"foo","Data":"YmFy"}}}
{
  "FunctionX1": {
    "item": {
      "Description": "foo",
      "Data": "YmFy"
    }
  }
}

Go Playground上试试这个。