json.Unmarshal се проваля, когато вграденият тип има UnmarshalJSON

Опитвам се да демаршалирам структура, която има вграден тип. Когато вграденият тип има метод 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'

... така че и двете персонализирани unmarshal функции се изпълниха. Стойността от вградената структура е правилна, но стойността от външната структура е загубена.

Ако просто премахнем метода EmbeddedStruct.UnmarshalJSON, той работи както се очаква.

Правя ли нещо нередно? Това очаквано ли е? Или бъг? Сигурен съм, че има начин да променя моите методи на UnmarshalJSON, за да заработи.


person David Brophy    schedule 16.04.2015    source източник


Отговори (1)


Очаква се.

Когато създавате псевдонима:

type Alias Foo

Alias няма да наследи методите на Foo, тъй като е различен тип с различен набор от методи, което искахте да постигнете, за да избегнете безкрайна рекурсия.

Въпреки това, вграденият метод UnmarshalJSON на EmbeddedStruct вместо това ще бъде повишен!

И така, Alias ще има метод UnmarshalJSON, който само ще демаршалира стойността на EmbeddedStruct, вместо да използва демаршалинга по подразбиране, който желаете.

person ANisus    schedule 16.04.2015
comment
Ааааххх разбирам. Благодаря! - person David Brophy; 16.04.2015
comment
@DavidBrophy Все още се опитвам да разбера как всъщност можете да заобиколите проблема. Ще редактирам отговора, ако го разбера. Но заповядайте :) - person ANisus; 16.04.2015
comment
Да, същото и тук! Всъщност току-що намерих дублиран въпрос, който не стига до никакво заключение: stackoverflow.com/questions/20587157/ - person David Brophy; 16.04.2015
comment
Заобиколих го, като направих копие на целия пакет encoding/json и добавих нова функция UnmarshalWithoutCustomUnmarshalers. Не е идеален, но работи перфектно... Ще натисна кода в github в даден момент. - person David Brophy; 20.04.2015