Мой вопрос очень похож на Вот этот, однако вместо преобразования 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!"}

Вы должны написать свою собственную (не) функцию маршалинга, в которой вы обрабатываете свои преобразования / условия и обрабатываете их как аргумент при вызове (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.
Это псевдоним нет! Id - это просто именованный тип, а objectid.ObjectId - базовый тип. Это не алиасинг!
@Volker Спасибо, исправлено.
Я использую ту же структуру для извлечения данных из MongoDB, поэтому я действительно не могу контролировать типы в структуре. (Или, по крайней мере, мне пришлось бы решать эту же проблему с другого конца)