2015-06-17 2 views
8

У меня есть несколько структур, которые требуют пользовательской сортировки. Когда я тестировал, я использовал JSON и стандартный маршаллер JSON. Поскольку он не маршали неэкспортированные поля, мне нужно было написать пользовательскую функцию MarshalJSON, которая отлично работала. Когда я вызывал json.Marshal в родительской структуре, содержащей те, которые нуждались в настройке сортировки в качестве полей, он работал нормально.Обработка пользовательских BSON Marshaling (Golang & mgo)

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

currency.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 
    } 
} 

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

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

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

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

+0

Я полагаю, тот факт, что валюты структура является объявлено с использованием невыполненных полей, является опечаткой? – SirDarius

+1

Нет, это преднамеренно. Существует больше кода, чем то, что выше, и я большой сторонник использования геттеров/сеттеров, чтобы остановить программиста, чтобы он мог просто изменить то, что они хотят, не обращая внимания на неизменную бизнес-логику, плюс слой абстракции означает любое изменение позже по строке к внутренней работе моей структуры означает, что мне нужно изменить минимальный код. – leylandski

+0

А также, если вы являетесь пользователем пакета 'shoppring/decimal', поля не экспортируются - поэтому в любом случае вам все равно придется определять пользовательский Getter/Setter, чтобы включить сериализацию/десериализацию, как показано в ответ. –

ответ

13

Пользовательские BSON Marshalling/Демаршаллизация работает почти таким же образом, вы должны реализовать интерфейсы Getter и Setter соответственно

Что-то, как это должно работать:

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, 
    } 
} 

// 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 
    } 
} 
+1

Это именно то, что я искал! Это досадно, что они не назвали его похожим на JSON, но что вы можете сделать. – leylandski

+2

Единственное изменение, необходимое для того, чтобы сделать это идеальным решением, состоит в том, чтобы удалить утверждение bson.Marshal вокруг структуры return в методе get, как описано в [этом ответе] (http://stackoverflow.com/questions/30895854/why-wont -mgo-unmarshall-my-struct-correct/30897080 # 30897080) – leylandski

+0

@Adam: В самом деле, спасибо. Отредактировал свой ответ, чтобы отразить его – HectorJ

Смежные вопросы