golang How to customize json Serialization application details

  • 2020-06-15 09:16:39
  • OfStack

preface

Go, developed by Google and billed as the Internet's C language, naturally supports the JSON format well. This article is mainly about the golang custom json serialization application, so let's start with the details

Problem is introduced into

When an struct exists with a field of type string or []byte but actually holds data in json format, json serialization occurs, for example


type Message struct {
 From string  `json:"from"`
 To string  `json:"to"`
 Data string `json:"data"`
}

func main() {
 msg := Message{
  From: "XiaoMing",
  To: "LiGang",
  Data: `{"title":"test","body":"something"}`,
 }
 jsonData, err := json.Marshal(msg)
 if err != nil {
  panic(err)
 }
 fmt.Println(string(jsonData))
}

In the above example, the Data field is of type string, but the content is saved in json format, at which point the program outputs:

[

{"from":"XiaoMing","to":"LiGang","data":"{\"title\":\"test\",\"body\":\"something\"}"}

]

As you can see, the serialized data is 1 string.

If Message corresponds to a table in the database and the data field in the database is of type json, when we need an interface, query the record in the Message table and return it to the client. If serialization is performed directly, the Data fetched by the client is actually a string, and the client needs to deserialize the string itself with json.

At this point we wonder, is there a way to serialize the data field to an json object instead of a string when the server serializes Message?

Custom serialization

Since the value of the data field is itself of type json, why not use it directly when serializing?

Looking at the official documentation for the json package, we can find examples of custom serialization

When performing the json serialization, if the corresponding type implements the Marshaler interface:


type Marshaler interface {
 MarshalJSON() ([]byte, error)
}

Its MarshalJSON method is executed and the returned byte array is serialized as the value.

So back to the above example, we can easily achieve the goal:


type JsonString string

func (j JsonString) MarshalJSON() ([]byte, error) {
 fmt.Println("marshal...")
 return []byte(j), nil
}

type Message struct {
 From string  `json:"from"`
 To string  `json:"to"`
 Data JsonString `json:"data"`
}

The above code declares JsonString based on the string type, representing the json format string, and implements the Marshaler interface. Because JsonString represents the json string, it is simply converted back into a byte array.

Then replace the Data field in Message with the JsonString type.

After executing the program again, you can see:


{"from":"XiaoMing","to":"LiGang","data":{"title":"test","body":"something"}}

Perfect!

conclusion


Related articles: