Search code examples
jsonmongodbgomarshalling

Go Convert type when marshaling to json


My question is very similar to this one, however instead of converting a float64 to a string which is handled using the string tag. In my case I'm trying to convert a ObjectID to a string using it's .Hex() method. And, vice versa using the .FromHex() function on the way back.

However, more generically how do I convert from type X to type Y & back during the Marshal & Unmarshaling?

My Example:

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))

}

Output:

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

Whereas, what I'd like is:

Json: {"id":"5b14dd20f6418c8443a5ffec","greeting":"Hello, World!"}

Solution

  • You should write your own (un)marshalling function in which you process your conversions/conditions and handle it as argument in calling the json (un)marshalling.

    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,
       })
    }