Перейти к преобразованию типа при маршалинге в json

Мой вопрос очень похож на Вот этот, однако вместо преобразования float64 в string, который обрабатывается с помощью строковый тег. В моем случае я пытаюсь преобразовать ObjectID в строку, используя метод .Hex(). И наоборот, используя функцию .FromHex() на обратном пути.

Однако в более общем плане, как мне преобразовать тип X в тип Y и обратно во время Marshal и Unmarshaling?

Мой пример:

package main

import (
    "log"
    "fmt"
    "encoding/json"
    "github.com/mongodb/mongo-go-driver/bson/objectid"
)

type Greeting struct {
    Id          *objectid.ObjectID  `json:"id"`
    Greeting    string              `json:"greeting,omitempty"`
}


func main() {
    // Create ObjectID
    id, err := objectid.FromHex("5b14dd20f6418c8443a5ffec")
    if err != nil { log.Fatal(err) }

    // Create Greeting
    g := Greeting{&id, "Hello, World!"}

    // Marshal to json
    j, err := json.Marshal(g)
    if err != nil { log.Fatal(err) }

    // Print Json
    fmt.Printf("Json: %s", string(j))

}

Выход:

Json: {"id":[91,20,221,32,246,65,140,132,67,165,255,236],"greeting":"Hello, World!"}

А я бы хотел:

Json: {"id":"5b14dd20f6418c8443a5ffec","greeting":"Hello, World!"}
Как сделать HTTP-запрос в Javascript?
Как сделать HTTP-запрос в Javascript?
В JavaScript вы можете сделать HTTP-запрос, используя объект XMLHttpRequest или более новый API fetch. Вот пример для обоих методов:
1
0
1 222
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы должны написать свою собственную (не) функцию маршалинга, в которой вы обрабатываете свои преобразования / условия и обрабатываете их как аргумент при вызове (un) маршалинга json.

type Whatever struct {
   someField int
}

func (w Whatever) MarshalJSON() ([]byte, error) {
    return json.Marshal(struct{
        SomeField int `json:"some_field"`
    }{
        SomeField: w.someField,
    })
}

func (w Whatever) MarshalJSON() ([]byte, error) {
   return json.Marshal(map[string]interface{}{
       "some_field": w.SomeField,
   })
}

Вы можете объявить именованный тип для objectid.ObjectId, который будет реализовывать интерфейс json.Marshaler, чтобы переопределить стандартный маршалинг и вместо этого вывести шестнадцатеричную строку:

type Id objectid.ObjectId

func (id Id) MarshalJSON() ([]byte, error) {
    return json.Marshal(objectid.ObjectId(id).Hex())
}

И используйте его вместо objectid.ObjectId в своих структурах:

type Greeting struct {
    Id Id
    Greeting string
}

Теперь, когда вы маршалируете Greeting, пакет json будет маршалировать поле Greeting, как ожидалось, но поскольку поле Id реализует json.Marshaler, оно будет маршалировано Id.MarshalJSON, который выведет id.Hex().

Вы можете сделать то же самое для демаршалинга, реализовав интерфейс json.Unmarshaler для Id.

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

Aaron N. Brock 05.06.2018 04:44

Это псевдоним нет! Id - это просто именованный тип, а objectid.ObjectId - базовый тип. Это не алиасинг!

Volker 05.06.2018 06:00

@Volker Спасибо, исправлено.

Zippo 05.06.2018 08:40

Другие вопросы по теме