如何在UnmarshalJSON中调用json.Unmarshal而不引起堆栈溢出?

如何在UnmarshalJSON中调用json.Unmarshal而不引起堆栈溢出?

问题描述:

How can I create a method UnmarshalJSON inside a struct, use json.Unmarshal inside without causing stack overflow?

package xapo

type Xapo struct {}

func (x Xapo) UnmarshalJSON(data []byte) error {
    err := json.Unmarshal(data, &x)
    if err != nil {
        return err
    }
    fmt.Println("done!")
    return nil
}

Can someone explain me why the stack overflow happens? Can it be fixed?

Thanks in advance.

It looks like you may be trying to do custom unmarshaling by using the default unmarshaler and then post-processing the data. However, as you've discovered, the obvious way of trying this causes an infinite loop!

The usual workaround is to create a new type using your type, use the default unmarshaler on an instance of the new type, post-process the data, and then finally cast to the original type and assign back to the target instance. Note that you'll want to implement UnmarshalJSON on a pointer type.

For example:

func (x *Xapo) UnmarshalJSON(data []byte) error {
  // Create a new type from the target type to avoid recursion.
  type Xapo2 Xapo

  // Unmarshal into an instance of the new type.
  var x2 Xapo2
  err := json.Unmarshal(data, &x2)
  if err != nil {
    return err
  }

  // Perform post-processing here.
  // TODO

  // Cast the new type instance to the original type and assign.
  *x = Xapo(x2)
  return nil
}