Изменение тегов JSON в структуре с помощью специального MarshalJSON - PullRequest
0 голосов
/ 07 июня 2018

Мы получаем некоторый JSON-ввод, демаршируем, выполняем некоторую работу, затем маршалируем и отправляем куда-то еще.JSON, который мы получаем, может иметь поле с именем «user».Когда мы возвращаемся в JSON, нам нужно изменить это поле «user» на «username».Мы можем сделать это, создав новую структуру со всеми одинаковыми полями, но с разными тегами JSON, но это кажется немного громоздким.Я думал, что здесь будет работать собственный маршаллер, но я немного застрял.Рассмотрим следующий код.

package main

import (
    "encoding/json"
    "fmt"
)

type StructA struct {
    Username string `json:"user"`
    Process  string `json:"process"`
}

func main() {

    var test1 StructA
    err := json.Unmarshal([]byte(`{"user": "user123", "process": "something"}`), &test1)
    if err != nil {
        fmt.Println(err)
    }

    // do some work with test1

    jsonByte, err := json.Marshal(&test1)
    if err != nil {
        fmt.Println(err)
    }

    fmt.Println(string(jsonByte))

}

func (u *StructA) MarshalJSON() ([]byte, error) {
    type Alias StructA
    return json.Marshal(&struct {
        Username string `json:"username"`
        *Alias
    }{
        Username: u.Username,
        Alias:    (*Alias)(u),
    })
}

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

В идеале это позволило бы мне изменить тег JSON в этом поле с «user» на «username».Тем не менее, я получаю «username» и «user».

{"username":"user123","user":"user123","process":"something"}

Я, конечно, мог бы создать совершенно новую структуру, которая отражает StructA с нужными мне тегами, но мне не нужно копировать каждыйединое поле и беспокоиться о синхронизации этих двух структур.Это не конец света, но это не кажется хорошим подходом.

Для ясности, конечный результат, который я ищу, следующий:

{"username":"user123","process":"something"}

Я уверен, что упускаю что-то тривиальное здесь, но это была длинная неделя, и любая помощь будет оценена.Спасибо!

Ответы [ 2 ]

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

используйте отражение для создания структуры и изменения ее тега

package main

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

type StructA struct {
    Username string `json:"user"`
    Process  string `json:"process"`
}

func main() {

    var test1 StructA
    err := json.Unmarshal([]byte(`{"user": "user123", "process": "something"}`), &test1)
    if err != nil {
        fmt.Println(err)
    }

    // do some work with test1

    jsonByte, err := json.Marshal(&test1)
    if err != nil {
        fmt.Println(err)
    }

    fmt.Println(string(jsonByte))

}

func (u *StructA) MarshalJSON() ([]byte, error) {
    // get old struct fields
    uType := reflect.TypeOf(u).Elem()
    userNameField, _ := uType.FieldByName("Username")
    // set username field tag
    userNameField.Tag = `json:"username"`
    processField, _ := uType.FieldByName("Process")
    newType := reflect.StructOf([]reflect.StructField{userNameField, processField})
    // set new value field
    oldValue := reflect.ValueOf(u).Elem()
    newtValue := reflect.New(newType).Elem()
    for i := 0; i < oldValue.NumField(); i++ {
        newtValue.Field(i).Set(oldValue.Field(i))
    }
    return json.Marshal(newtValue.Interface())
}
0 голосов
/ 08 июня 2018

Одним из вариантов может быть наличие одной структуры с неизменяющимися значениями и двух альтернативных структур, которые включают эту структуру и имеют только изменяющиеся значения.Затем вы используете один для демаршалинга, а второй - для маршалинга.

type StructA struct {
    Process  string `json:"process"`
    ...
}

type WithUser struct {
    StructA
    Username `json:"user"`
}

type WithUsername struct {
    StructA
    Username `json:"username"`
}

Это потребует нескольких структур, но без дублирования в каждом и может быть достаточно гибким в том, что вы включаете, вместо жесткого кодирования того, что вы хотитепревратить в пользовательскую функцию маршала.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...