JSON Маршалинг составных структур, которые оба реализуют MarshalJSON () - PullRequest
0 голосов
/ 13 июня 2018

Я недавно столкнулся со следующей проблемой и не нашел никакого решения.У меня есть два типа структуры в Go, давайте назовем их Parent и Child.Child имеет анонимное поле типа * Parent.Однако у Parent есть поле с именем «ID», которое имеет тип третьей структуры, тип которой мы будем называть «IDType» (в моей реальной проблеме это диалект / sql.NullInt64).IDType имеет поле int и поле bool.

Проблема заключается в следующем: Оба, Parent и Child, реализуют MarshalJSON (), потому что для Parent я хочу, чтобы только поле int внутри JSON и для Child было одинаковым.Однако, похоже, что оба MarshalJSON выводят, что в окончательном JSON кодируются только значения Parent.

Возможно, минимальный пример облегчает понимание:

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 голосов
/ 13 июня 2018

Похоже, вы определяете только собственную логику маршалинга из-за маршалинга пользовательских 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 .

0 голосов
/ 13 июня 2018

Вы должны иметь именованный указатель на родителя или встраиваемое значение Parent.

Опция 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}

Еще один хакерский вариант - отдельно маршаловать родителя и потомка, а затем соединять вручную, обрезая последние / первые символы, соединяя с , и заключая в {}.

...