Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON marshalling/unmarshalling same struct to different JSON format in go?

I have a struct that I'd like to Marshal into JSON differently depending on the context.

For example, sometimes I want to marshal like this:

    type MyStruct struct {
        Nickname       string `json:"nickname"`
        EmailAddress   string `json:"email_address"`
        PhoneNumber    string `json:"-"`
        MailingAddress string `json:"-"`
    }

And sometimes I want to marshal like this:

    type MyStruct struct {
        Nickname       string `json:"nickname"`
        EmailAddress   string `json:"email_address"`
        PhoneNumber    string `json:"phone_number"`
        MailingAddress string `json:"mailing_address"`
    }

Is there a simple way to do this without:

  1. Making 2 separate structs.
  2. Writing a custom marshaller.
  3. Temporarily removing the string values for PhoneNumber and MailingAddress (with an omitempty on the tag), marshaling and then adding them back.

If only there was a way to:

  1. Specify 2 sets of tags and tell the marshaler which ones to use.
  2. Dynamically change the tags at runtime.
like image 440
Karlie Verkest De Young Avatar asked Oct 10 '14 16:10

Karlie Verkest De Young


People also ask

What is the difference between Marshal and Unmarshal in Golang?

Unmarshal is the contrary of marshal. It allows you to convert byte data into the original data structure. In go, unmarshaling is handled by the json.

What is marshalling and unmarshalling in JSON?

JSON has 3 basic types: booleans, numbers, strings, combined using arrays and objects to build complex structures. Go's terminology calls marshal the process of generating a JSON string from a data structure, and unmarshal the act of parsing JSON to a data structure.

How do you struct a marshal in Golang?

In Golang, struct data is converted into JSON and JSON data to string with Marshal() and Unmarshal() method. The methods returned data in byte format and we need to change returned data into JSON or String. In our previous tutorial, we have explained about Parsing JSON Data in Golang.

How does JSON Unmarshal work Golang?

To unmarshal a JSON array into a slice, Unmarshal resets the slice length to zero and then appends each element to the slice. As a special case, to unmarshal an empty JSON array into a slice, Unmarshal replaces the slice with a new empty slice.


1 Answers

I know you explicitly mention "without writing a custom marshaler", but in case someone sees this and thinks it should be avoided because of complexity, a custom marshaler to do what you want to do is really simple:

type MyStruct struct {
    Nickname       string `json:"nickname"`
    EmailAddress   string `json:"email_address"`
    PhoneNumber    string `json:"phone_number"`
    MailingAddress string `json:"mailing_address"`
    all            bool
}

func (ms MyStruct) MarshalJSON() ([]byte, error) {
    m := map[string]interface{}{} // ideally use make with the right capacity
    m["nickname"] = ms.Nickname
    m["email_address"] = ms.EmailAddress
    if ms.all {
        m["phone_number"] = ms.PhoneNumber
        m["mailing_address"] = ms.MailingAddress
    }
    return json.Marshal(m)
}

If the all field should be set by an external package, then a method could be defined on the struct, or the field could be made public (wouldn't affect the JSON since it is encoded via the custom marshaler).

Runnable example on the playground: http://play.golang.org/p/1N_iBzvuW4

like image 95
mna Avatar answered Oct 23 '22 17:10

mna