diff --git a/bson/bson.go b/bson/bson.go index d960f7a37..31beab191 100644 --- a/bson/bson.go +++ b/bson/bson.go @@ -698,9 +698,21 @@ func getStructInfo(st reflect.Type) (*structInfo, error) { info := fieldInfo{Num: i} tag := field.Tag.Get("bson") - if tag == "" && strings.Index(string(field.Tag), ":") < 0 { - tag = string(field.Tag) + + // Fall-back to JSON struct tag, if feature flag is set. + if tag == "" && useJSONTagFallback { + tag = field.Tag.Get("json") } + + // If there's no bson/json tag available. + if tag == "" { + // If there's no tag, and also no tag: value splits (i.e. no colon) + // then assume the entire tag is the value + if strings.Index(string(field.Tag), ":") < 0 { + tag = string(field.Tag) + } + } + if tag == "-" { continue } diff --git a/bson/compatability_test.go b/bson/compatability_test.go new file mode 100644 index 000000000..743a00e8a --- /dev/null +++ b/bson/compatability_test.go @@ -0,0 +1,54 @@ +package bson_test + +import ( + "github.com/globalsign/mgo/bson" + . "gopkg.in/check.v1" +) + +type mixedTagging struct { + First string + Second string `bson:"second_field"` + Third string `json:"third_field"` + Fourth string `bson:"fourth_field" json:"alternate"` +} + +// TestTaggingFallback checks that tagging fallback can be used/works as expected. +func (s *S) TestTaggingFallback(c *C) { + initial := &mixedTagging{ + First: "One", + Second: "Two", + Third: "Three", + Fourth: "Four", + } + + // Take only testing.T, leave only footprints. + initialState := bson.JSONTagFallbackState() + defer bson.SetJSONTagFallback(initialState) + + // Marshal with the new mode applied. + bson.SetJSONTagFallback(true) + bsonState, errBSON := bson.Marshal(initial) + c.Assert(errBSON, IsNil) + + // Unmarshal into a generic map so that we can pick up the actual field names + // selected. + target := make(map[string]string) + errUnmarshal := bson.Unmarshal(bsonState, target) + c.Assert(errUnmarshal, IsNil) + + // No tag, so standard naming + _, firstExists := target["first"] + c.Assert(firstExists, Equals, true) + + // Just a BSON tag + _, secondExists := target["second_field"] + c.Assert(secondExists, Equals, true) + + // Just a JSON tag + _, thirdExists := target["third_field"] + c.Assert(thirdExists, Equals, true) + + // Should marshal 4th as fourth_field (since we have both tags) + _, fourthExists := target["fourth_field"] + c.Assert(fourthExists, Equals, true) +} diff --git a/bson/compatibility.go b/bson/compatibility.go new file mode 100644 index 000000000..6afecf53c --- /dev/null +++ b/bson/compatibility.go @@ -0,0 +1,16 @@ +package bson + +// Current state of the JSON tag fallback option. +var useJSONTagFallback = false + +// SetJSONTagFallback enables or disables the JSON-tag fallback for structure tagging. When this is enabled, structures +// without BSON tags on a field will fall-back to using the JSON tag (if present). +func SetJSONTagFallback(state bool) { + useJSONTagFallback = state +} + +// JSONTagFallbackState returns the current status of the JSON tag fallback compatability option. See SetJSONTagFallback +// for more information. +func JSONTagFallbackState() bool { + return useJSONTagFallback +}