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'

... так что обе пользовательские функции демаршалирования работали. Значение из встроенной структуры правильное, но значение из внешней структуры потеряно.

Если мы просто удалим метод 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