json.Unmarshal fails when embedded type has UnmarshalJSON

落爺英雄遲暮 提交于 2019-12-10 15:31:58

问题


I'm trying to unmarshal a struct that has an embedded type. When the embedded type has an UnmarshalJSON method, the unmarshaling of the outer type fails:

https://play.golang.org/p/Y_Tt5O8A1Q

package main


import (
    "fmt"

    "encoding/json"
)

type Foo struct {
    EmbeddedStruct
    Field string
}

func (d *Foo) UnmarshalJSON(from []byte) error {
    fmt.Printf("Foo.UnmarshalJSON\n")

    type Alias Foo
    alias := &Alias{}
    if err := json.Unmarshal(from, alias); err != nil {
        return fmt.Errorf("Error in Foo.UnmarshalJSON: json.Unmarshal returned an error:\n%v\n", err)
    }
    *d = Foo(*alias)

    return nil
}

type EmbeddedStruct struct {
    EmbeddedField string
}

func (d *EmbeddedStruct) UnmarshalJSON(from []byte) error {
    fmt.Printf("EmbeddedStruct.UnmarshalJSON\n")

    type Alias EmbeddedStruct
    alias := &Alias{}
    if err := json.Unmarshal(from, alias); err != nil {
        return fmt.Errorf("Error in EmbeddedStruct.UnmarshalJSON: json.Unmarshal returned an error:\n%v\n", err)
    }
    *d = EmbeddedStruct(*alias)

    return nil
}

func main() {

    data := `{"EmbeddedField":"embeddedValue", "Field": "value"}`
    foo := &Foo{}

    json.Unmarshal([]byte(data), foo)

    fmt.Printf("Foo: %v\n", foo)

    if foo.EmbeddedField != "embeddedValue" {
        fmt.Printf("Unmarshal didn't work, EmbeddedField value is %v. Should be 'embeddedValue'\n", foo.EmbeddedField)
    }

    if foo.Field != "value" {
        fmt.Printf("Unmarshal didn't work, Field value is %v. Should be 'value'\n", foo.Field)
    }

}

The output is:

Foo.UnmarshalJSON
EmbeddedStruct.UnmarshalJSON
Foo: &{{embeddedValue} }
Unmarshal didn't work, Field value is . Should be 'value'

... so both custom unmarshal functions ran. The value from the embedded struct is correct, but the value from the outer struct is lost.

If we simply remove the EmbeddedStruct.UnmarshalJSON method, it works as expected.

Am I doing something wrong? Is this expected? Or a bug? I'm sure there's a way I can tweak my UnmarshalJSON methods to get it working.


回答1:


It is expected.

When you create the alias:

type Alias Foo

Alias will not inherit the methods of Foo since it is a different type with a different method set, which is what you wanted to achieve to avoid an infinite recursion.

However, the embedded EmbeddedStruct's UnmarshalJSON method will instead be promoted!

So, Alias will have an UnmarshalJSON method that will only unmarshal EmbeddedStruct's value, instead of using the default unmarshalling that you desired.



来源:https://stackoverflow.com/questions/29667379/json-unmarshal-fails-when-embedded-type-has-unmarshaljson

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!