Структура GoLang не отменяет маршалирование должным образом при использовании пользовательского демаршала для вложенной структуры - PullRequest
0 голосов
/ 12 сентября 2018

Нам нужно использовать пользовательский демаршалер для структуры, вложенной во множество других структур, для которых не требуется пользовательский демаршалер. У нас есть много структур, похожих на структуру B, определенную ниже (как во вложении A). Код выводится true false 0 (ожидается true false 2). Есть идеи?


Пример с Go Playground здесь .

package main

import (
    "fmt"
    "encoding/json"
)

type A struct {
    X bool `json:"x"`
    Y bool `json:"y"`
}

type B struct {
    A
    Z int `json:"z"`
}

func (a *A) UnmarshalJSON(bytes []byte) error {
    var aa struct {
        X string `json:"x"`
        Y string `json:"y"`
    }
    json.Unmarshal(bytes, &aa)

    a.X = aa.X == "123"
    a.Y = aa.Y == "abc"
    return nil
}

const myJSON = `{"x": "123", "y": "fff", "z": 2}`

func main() {
    var b B
    json.Unmarshal([]byte(myJSON), &b)
    fmt.Print(b.X," ",b.Y," ",b.Z)
}

РЕДАКТИРОВАТЬ: вопрос был помечен как дубликат здесь , но если сделать A явным полем, наш API будет загроможден. Также после создания A явного поля результат будет false false 2, так что это не поможет вообще.

1 Ответ

0 голосов
/ 13 сентября 2018

Поскольку B встраивает A, A.UnmarshalJSON() отображается как B.UnmarshalJSON().Из-за этого B реализует json.Unmarshaler и в результате json.Unmarshal() вызывает B.UnmarshalJSON(), который только демаршал поля A.По этой причине B.Z не устанавливается из JSON.

Это самый простой способ, который я мог бы придумать, чтобы заставить его работать в соответствии с вашим ограничением не изменять типы данных в A:

  1. Заставить B встроить другую структуру C, содержащую поля, не содержащиеся в A.
  2. Написать метод UnmarshalJSON () для B, который демаршализирует один и тот же JSON как в BA, так и в BC. ПреимуществоОпределение другого типа C с полями, не входящими в A, заключается в том, что вы можете делегировать его демаршаллинг в пакет json.

С новым методом B.UnmarshalJSON() вы теперь имеете полный контроль над демонтажем полей за пределамиA также.

type A struct {
    X bool `json:"x"`
    Y bool `json:"y"`
}

func (a *A) UnmarshalJSON(bytes []byte) error {
    // the special unmarshalling logic here
}

type C struct {
    Z int `json:"z"`
}

type B struct {
    A
    C
}

func (b *B) UnmarshalJSON(bytes []byte) error {
    if err := json.Unmarshal(bytes, &b.A); err != nil {
        return err
    }
    if err := json.Unmarshal(bytes, &b.C); err != nil {
        return err
    }
    return nil
}
...