encoding/json: promoted Unmarshal method on embedded field caused confusion

In a follow-up post, officials replied this morning:


The Num field will not be unmarshaled because the Object method will not be executed due to the promotion of Nested fields. The explanation in the previous passage is similar. But there are two more elegant ways to solve this problem. Let’s take a look at the big guy’s code.

Method a

Just add the following line to the code:

var _ json.Unmarshaler = (*Object)(nil)
Copy the code
package main

import (
 "encoding/json"
 "fmt"
 "time" )  var testJSON = `{"num":5,"duration":"5s"}`  type Nested struct {  Dur time.Duration `json:"duration"` }  func (obj *Object) UnmarshalJSON(data []byte) error {  tmp := struct {  Dur string `json:"duration"`  Num int `json:"num"` } {} iferr := json.Unmarshal(data, &tmp); err ! =nil {  return err  }   dur, err := time.ParseDuration(tmp.Dur)  iferr ! =nil {  return err  }  obj.Dur = dur  obj.Num = tmp.Num  return nil }  type Object struct {  Nested  Num int `json:"num"` }  var _ json.Unmarshaler = (*Object)(nil)  func main(a) {  obj := Object{}  _ = json.Unmarshal([]byte(testJSON), &obj)  fmt.Printf("result: %+v \n", obj) } Copy the code

Type assertion will be a nice guide for embedded fields where interface methods are implemented. Adding these types of assertions is a good practice to help you quickly catch potential bugs.

Method b

Implement custom Time unmarshaller.

package main

import (
 "encoding/json"
 "fmt"
 "time" )  var testJSON = `{"num":5,"duration":"5s"}`  type customTimeDuration time.Duration  type Nested struct {  Dur customTimeDuration `json:"duration"` }  func (ctd *customTimeDuration) UnmarshalJSON(b []byte) error {  var durStr string  iferr := json.Unmarshal(b, &durStr); err ! =nil {  return err  }  dur, err := time.ParseDuration(durStr)  if err == nil {  *ctd = customTimeDuration(dur)  }  return err }  type Object struct {  Nested  Num int `json:"num"` }  func main(a) {  obj := Object{}  _ = json.Unmarshal([]byte(testJSON), &obj)  fmt.Printf("result: %+v \n", obj) } Copy the code

This approach is similar to the separate parsing in the previous article, where he redeclares the alias type and then implements the UnmarshalJson interface for the alias type. I prefer the first method of adding type assertions, which is concise and easy to understand and less intrusive to code.

The official response to the question was enthusiastic, noting that his own team had encountered the exact same problem a few years ago, and that he understood the developer’s feelings and wrote a similar article on the subject at the time, https://medium.com/@odeke_et/compile-type-assertions-to-the-rescue-6ddab4b8398b. What did I say? It’s a pit trodden by others, a pit trodden by future generations, and a pit trodden by future generations.

U1s1, the big guy gives the scheme and code is still very pleasing to the eye, worth learning (copy).

—————————— END ———————————-