当嵌入类型具有UnmarshalJSON方法时,json.Unmarshal失败

7
我正在尝试解析一个包含嵌入类型的结构体。当嵌入类型具有UnmarshalJSON方法时,外部类型的解析失败: 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)
    }

}

输出结果如下:
Foo.UnmarshalJSON
EmbeddedStruct.UnmarshalJSON
Foo: &{{embeddedValue} }
Unmarshal didn't work, Field value is . Should be 'value'

...因此两个自定义反解函数都运行了。嵌入结构中的值是正确的,但外部结构中的值丢失了。

如果我们简单地删除EmbeddedStruct.UnmarshalJSON方法,它就像预期的那样工作。

我做错了什么吗?这是预期的结果吗?还是一个错误?我相信有一种方法可以调整我的UnmarshalJSON方法使其正常工作。

1个回答

10

预计会发生。

当您创建别名时:

type Alias Foo

Alias不会继承Foo的方法,因为它是一种不同的类型,具有不同的方法集,这正是你想要实现的,以避免无限递归。

然而,嵌入式EmbeddedStructUnmarshalJSON方法将被提升!

因此,Alias将拥有一个UnmarshalJSON方法,该方法仅解组EmbeddedStruct的值,而不是使用你所期望的默认解组方式。


啊哈,我明白了。谢谢! - David Brophy
@DavidBrophy 我还在努力想办法解决这个问题。如果我找到了解决方法,我会编辑答案的。但是,不用谢 :) - ANisus
是的,我也一样!实际上我刚刚发现了一个没有得出任何结论的重复问题:http://stackoverflow.com/questions/20587157/golang-having-trouble-with-nested-json-unmarshaler - David Brophy
我通过复制整个encoding/json包并添加一个名为“UnmarshalWithoutCustomUnmarshalers”的新函数来解决了这个问题。虽然不是理想的解决方案,但它完美地解决了问题...我会在某个时候将代码推送到github上。 - David Brophy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接