复合结构的JSON Marshaling,它们都实现了MarshalJSON()

时间:2018-06-13 07:59:53

标签: json go struct marshalling

我最近遇到了以下问题,但没有找到任何解决方案。我在Go中有两个结构类型,让我们称它们为Parent和Child。 Child有一个* Parent类型的匿名字段。但是,Parent有一个名为“ID”的字段,它具有第三个结构的类型,我们将其称为“IDType”(在我的实际问题中,这是一个方言/ sql.NullInt64)。 IDType有一个int字段和一个bool字段。

问题如下:Parent和Child都实现了MarshalJSON(),因为对于Parent我只希望JSON内部的int字段和Child相同。但是,似乎两个MarshalJSON都推断出结果只有Parent的值在最终的JSON中编码。

也许一个最小的例子让它更容易理解:

package main

import (
    "encoding/json"
    "fmt"
    "os"
)

type IDType struct {
    Value int
    Valid bool
}

type Parent struct {
    ID         IDType `json:"id"`
    SomeString string `json:"some_string"`
}

type Child struct {
    *Parent
    Status int `json:"status"`
}

func (parent *Parent) MarshalJSON() ([]byte, error) {
    type Alias Parent
    fmt.Println("Parent")
    return json.Marshal(struct {
        *Alias
        ID int `json:"id"`
    }{
        Alias: (*Alias)(parent),
        ID:    parent.ID.Value,
    })
}

func (child *Child) MarshalJSON() ([]byte, error) {
    type Alias Child
    fmt.Println("Child")
    return json.Marshal(struct {
        *Alias
        Status int `json:"status"`
    }{
        Alias:  (*Alias)(child),
        Status: child.Status,
    })
}

func main() {
    ID := IDType{Value: 1, Valid: true}
    parent := Parent{ID: ID, SomeString: "Hello"}
    child := Child{Parent: &Parent{ID: ID, SomeString: "Hello"}, Status: 1}
    json.NewEncoder(os.Stdout).Encode(&parent)
    json.NewEncoder(os.Stdout).Encode(&child)
}

输出结果为:

Parent
{"some_string":"Hello","id":1}
Child
Parent
{"some_string":"Hello","id":1}

我期待的是:

Parent
{"some_string":"Hello","id":1}
Child
Parent
{"some_string":"Hello","id":1, "status": 1}

2 个答案:

答案 0 :(得分:2)

由于自定义ID编组,您看起来只定义了自定义封送逻辑。仅定义未嵌入的IDType类型的自定义编组,因此不会对其他类型的编组造成任何问题:

func (id *IDType) MarshalJSON() ([]byte, error) {
    return json.Marshal(id.Value)
}

并且不需要其他自定义编组。有了这个,输出将是:

{"id":1,"some_string":"Hello"}
{"id":1,"some_string":"Hello","status":1}

Go Playground上尝试。

答案 1 :(得分:1)

您应该具有指向父级的父级或嵌入值的命名指针。

选项1将为您提供您期望的JSON。

type Child struct {
    Parent
    Status int `json:"status"`
}
>> {"some_string":"Hello","id":1, "status": 1}

选项2将父项作为子节点。

type Child struct {
    Parent *Parent
    Status int `json:"status"`
}
>> {Parent: {"some_string":"Hello","id":1}, "status": 1}

另一个愚蠢的选择是组织父母&单独的子项,然后通过剪切最后/第一个字符手动加入,加入,并换入{}