2015-06-17 24 views
8

Mam wiele struktur, które wymagają niestandardowego zestawiania. Kiedy testowałem, korzystałem z JSON-a i standardowego koordynatora JSON. Ponieważ nie zajmuje się niezbadanymi polami, musiałem napisać niestandardową funkcję MarshalJSON, która działała idealnie. Kiedy zadzwoniłem do json.Marshal na strukturę nadrzędną zawierającą te, które wymagały niestandardowych ustawień jako pól, działało dobrze.Praca z niestandardowym BSON Marshaling (Golang & mgo)

Teraz potrzebuję zebrać wszystko do BSON dla niektórych prac MongoDB, i nie mogę znaleźć żadnej dokumentacji o tym, jak napisać niestandardowy rozkaz BSON. Czy ktoś może mi powiedzieć, jak zrobić ekwiwalent dla BSON/mgo za to, co pokazałem poniżej?

currency.go (istotne części)

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 (ponownie, tylko odpowiednie części)

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

Kiedy zadzwonić json.Marshal (p) gdzie p jest produktem, produkuje dane wyjściowe, które chcę, bez potrzeby stosowania wzorca (nie jestem pewien nazwy), w którym tworzysz strukturę, która jest po prostu klonem ze wszystkimi wyeksportowanymi polami.

Moim zdaniem zastosowanie metody inline, której używałem, znacznie upraszcza interfejs API i zatrzymuje dodatkowe struktury, które powodują problemy.

+0

Przypuszczam fakt, że struktura walutą jest zadeklarowane użycie nieodportowanych pól to literówka? – SirDarius

+1

Nie, to celowe. Jest więcej kodu niż to, co powyżej i jestem wielkim zwolennikiem używania getters/setters, aby zatrzymać programistę, który potrafi zmienić to, co chce, bez względu na niezmienną logikę biznesową, a warstwa abstrakcji oznacza każdą zmianę później w dół do wewnętrznego działania mojej struktury oznacza, że ​​muszę zmienić minimalną ilość kodu. – leylandski

+0

A także, jeśli jesteś użytkownikiem pakietu 'shopspring/decimal', pola nie są eksportowane - więc w obu przypadkach będziesz musiał zdefiniować niestandardowy program Getter/Setter, aby umożliwić serializację/deserialization, jak pokazano w odpowiedź. –

Odpowiedz

13

klienta bson Marshalling/Unmarshalling działa prawie tak samo, trzeba zaimplementować interfejsy Getter i Setter odpowiednio

Coś jak to powinno działać:

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

Tego właśnie szukałem! To trochę denerwujące, że nie nazwali go w podobny sposób jak JSON, ale co możesz zrobić. – leylandski

+2

Jedyną zmianą, która jest niezbędna do rozwiązania tego problemu, jest usunięcie instrukcji bson.Marshal wokół struktury return w metodzie get opisanej przez [ta odpowiedź] (http://stackoverflow.com/questions/30895854/why-wont -mgo-unmarshall-my-struct-properly/30897080 # 30897080) – leylandski

+0

@Adam: Rzeczywiście, dzięki. Zmieniono moją odpowiedź, aby to odzwierciedlić – HectorJ