/ / JSON немаршал ціле число в рядок - json, go, struct, unmarshalling

JSON немаршал ціле поле в рядок - json, go, struct, unmarshalling

Я борюся з deserializing ціле урядок структури структури. Поле struct є рядком і, як очікується, буде призначатися користувачам моєї бібліотеки. Ось чому я хочу, щоб це була рядок, оскільки для запису в базу даних я дійсно не дбаю про значення всередині. Користувачі можуть надавати текст, але деякі просто призначають цілі числа.

Розглянемо цю структуру:

type Test struct {
Foo string
}

Іноді я отримую значення JSON, яке є дійсним, але не "deserialize" у структуру, оскільки поле Foo є цілим числом замість рядка:

{ "foo": "1" } // works
{ "foo": 1 } // doesn"t

json.Unmarshal вибухне з такою помилкою: json: cannot unmarshal number into Go struct field test.Foo of type string

Див. https://play.golang.org/p/4Qau3umaVm

Тепер у кожній іншій бібліотеці JSON (в іншійЯ працював до цих пір, якщо цільове поле - це рядок, і ви отримаєте ціле число, то десеріализатор, як правило, просто обертає int в рядок і виконується з ним. Чи може це бути досягнуто в Go?

Так як я дійсно не можу контролювати, як надходять дані, мені потрібно зробити json.Unmarshal Нечутливий до цього - іншим рішенням було б визначити Foo as interface{} які безпідставно ускладнюють мій код з типовими твердженнями тощо.

Будь-які ідеї про те, як це зробити? Я в основному потребую зворотного json:",string"

Відповіді:

5 за відповідь № 1

Для обробки великих структур можна використовувати вбудовування.

Оновлено, щоб не відкидати, можливо, попередньо встановлені значення полів.

func (t *T) UnmarshalJSON(d []byte) error {
type T2 T // create new type with same structure as T but without its method set!
x := struct{
T2 // embed
Foo json.Number `json:"foo"`
}{T2: T2(*t)} // don"t forget this, if you do and "t" already has some fields set you would lose them

if err := json.Unmarshal(d, &x); err != nil {
return err
}
*t = T(x.T2)
t.Foo = x.Foo.String()
return nil
}

https://play.golang.org/p/BytXCeHMvt


1 для відповіді № 2

Ви можете налаштувати, як структура даних буде розмежовуватися шляхом реалізації json.Unamrshaler інтерфейс

Найпростіший спосіб обробляти невідомі типи - nnmarshal JSON в проміжну структуру і обробляти твердження типу і перевірку під час десериализации:

type test struct {
Foo string `json:"foo"`
}

func (t *test) UnmarshalJSON(d []byte) error {
tmp := struct {
Foo interface{} `json:"foo"`
}{}

if err := json.Unmarshal(d, &tmp); err != nil {
return err
}

switch v := tmp.Foo.(type) {
case float64:
t.Foo = strconv.Itoa(int(v))
case string:
t.Foo = v
default:
return fmt.Errorf("invalid value for Foo: %v", v)
}

return nil
}

https://play.golang.org/p/t0eI4wCxdB