Обработка пользовательского маршалинга BSON (Golang & mgo)

у меня есть несколько структур, которые требуют пользовательского маршалинга. Когда я тестировал, я использовал JSON и стандартный JSON marshaller. Поскольку он не маршалирует несообщаемые поля, мне нужно было написать пользовательскую функцию MarshalJSON, которая работала отлично. Когда я позвонил Джейсону.Маршал на родительской структуре, содержащей те, которые нуждались в пользовательском маршаллинге в качестве полей, он работал нормально.

теперь мне нужно маршалировать все в BSON для некоторой работы MongoDB, и я не могу найти никакой документации о том, как написать пользовательский маршаллинг BSON. Может ли кто-нибудь сказать мне, как сделать эквивалент для BSON/mgo для того, что я продемонстрировал ниже?

валюты.go (важные моменты)

type Currency struct {
    value        decimal.Decimal //The actual value of the currency.
    currencyCode string          //The ISO currency code.
}

/*
MarshalJSON implements json.Marshaller.
*/
func (c Currency) MarshalJSON() ([]byte, error) {
    f, _ := c.Value().Float64()
    return json.Marshal(struct {
        Value        float64 `json:"value" bson:"value"`
        CurrencyCode string  `json:"currencyCode" bson:"currencyCode"`
    }{
        Value:        f,
        CurrencyCode: c.CurrencyCode(),
    })
}

/*
UnmarshalJSON implements json.Unmarshaller.
*/
func (c *Currency) UnmarshalJSON(b []byte) error {

    decoded := new(struct {
        Value        float64 `json:"value" bson:"value"`
        CurrencyCode string  `json:"currencyCode" bson:"currencyCode"`
    })

    jsonErr := json.Unmarshal(b, decoded)

    if jsonErr == nil {
        c.value = decimal.NewFromFloat(decoded.Value)
        c.currencyCode = decoded.CurrencyCode
        return nil
    } else {
        return jsonErr
    }
}

продукта.go (опять же, только соответствующие части)

type Product struct {
    Name  string
    Code  string
    Price currency.Currency
}

когда я вызываю json.Маршал (p) где p-продукт, он производит вывод, который я хочу без необходимости в шаблоне (не уверен в имени), где вы создаете структуру, которая является просто клон все экспортируемые поля.

на мой взгляд, использование встроенного метода, который я использовал, значительно упрощает API и останавливает вас с дополнительными структурами, которые загромождают вещи.

1 ответов


пользовательский маршалинг BSON / Unmarshalling работает почти так же, как вы должны реализовать Геттер и сеттер интерфейсы соответственно

что-то вроде этого должно работать :

type Currency struct {
    value        decimal.Decimal //The actual value of the currency.
    currencyCode string          //The ISO currency code.
}

// GetBSON implements bson.Getter.
func (c Currency) GetBSON() (interface{}, error) {
    f := c.Value().Float64()
    return struct {
        Value        float64 `json:"value" bson:"value"`
        CurrencyCode string  `json:"currencyCode" bson:"currencyCode"`
    }{
        Value:        f,
        CurrencyCode: c.currencyCode,
    }, nil
}

// SetBSON implements bson.Setter.
func (c *Currency) SetBSON(raw bson.Raw) error {

    decoded := new(struct {
        Value        float64 `json:"value" bson:"value"`
        CurrencyCode string  `json:"currencyCode" bson:"currencyCode"`
    })

    bsonErr := raw.Unmarshal(decoded)

    if bsonErr == nil {
        c.value = decimal.NewFromFloat(decoded.Value)
        c.currencyCode = decoded.CurrencyCode
        return nil
    } else {
        return bsonErr
    }
}