Skip to content

Commit cd82ab3

Browse files
GODRIVER-3470 Revert changes to UnmarshalerDecodeValue
1 parent 75ee151 commit cd82ab3

File tree

2 files changed

+57
-12
lines changed

2 files changed

+57
-12
lines changed

bson/bsoncodec/default_value_decoders.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1569,18 +1569,6 @@ func (dvd DefaultValueDecoders) UnmarshalerDecodeValue(_ DecodeContext, vr bsonr
15691569
return ValueDecoderError{Name: "UnmarshalerDecodeValue", Types: []reflect.Type{tUnmarshaler}, Received: val}
15701570
}
15711571

1572-
// If BSON value is null and the go value is a pointer, then don't call
1573-
// UnmarshalBSON. Even if the Go pointer is already initialized (i.e.,
1574-
// non-nil), encountering null in BSON will result in the pointer being
1575-
// directly set to nil here. Since the pointer is being replaced with nil,
1576-
// there is no opportunity (or reason) for the custom UnmarshalBSON logic to
1577-
// be called.
1578-
if val.Kind() == reflect.Ptr && vr.Type() == bsontype.Null {
1579-
val.Set(reflect.Zero(val.Type()))
1580-
1581-
return vr.ReadNull()
1582-
}
1583-
15841572
if val.Kind() == reflect.Ptr && val.IsNil() {
15851573
if !val.CanSet() {
15861574
return ValueDecoderError{Name: "UnmarshalerDecodeValue", Types: []reflect.Type{tUnmarshaler}, Received: val}
@@ -1593,6 +1581,18 @@ func (dvd DefaultValueDecoders) UnmarshalerDecodeValue(_ DecodeContext, vr bsonr
15931581
return err
15941582
}
15951583

1584+
// If the target Go value is a pointer and the BSON field value is empty, set the value to the
1585+
// zero value of the pointer (nil) and don't call UnmarshalBSON. UnmarshalBSON has no way to
1586+
// change the pointer value from within the function (only the value at the pointer address),
1587+
// so it can't set the pointer to "nil" itself. Since the most common Go value for an empty BSON
1588+
// field value is "nil", we set "nil" here and don't call UnmarshalBSON. This behavior matches
1589+
// the behavior of the Go "encoding/json" unmarshaler when the target Go value is a pointer and
1590+
// the JSON field value is "null".
1591+
if val.Kind() == reflect.Ptr && len(src) == 0 {
1592+
val.Set(reflect.Zero(val.Type()))
1593+
return nil
1594+
}
1595+
15961596
if !val.Type().Implements(tUnmarshaler) {
15971597
if !val.CanAddr() {
15981598
return ValueDecoderError{Name: "UnmarshalerDecodeValue", Types: []reflect.Type{tUnmarshaler}, Received: val}

bson/unmarshaling_cases_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
"go.mongodb.org/mongo-driver/bson/bsonrw"
1313
"go.mongodb.org/mongo-driver/bson/bsontype"
14+
"go.mongodb.org/mongo-driver/bson/primitive"
1415
)
1516

1617
type unmarshalingTestCase struct {
@@ -194,6 +195,50 @@ func unmarshalingTestCases() []unmarshalingTestCase {
194195
want: &valNonPtrStruct,
195196
data: docToBytes(valNonPtrStruct),
196197
},
198+
{
199+
name: "nil pointer and non-pointer type with BSON minkey",
200+
sType: reflect.TypeOf(unmarshalBehaviorTestCase{}),
201+
want: &unmarshalBehaviorTestCase{
202+
BSONValueTracker: unmarshalBSONValueCallTracker{
203+
called: true,
204+
},
205+
BSONValuePtrTracker: &unmarshalBSONValueCallTracker{
206+
called: true,
207+
},
208+
BSONTracker: unmarshalBSONCallTracker{
209+
called: true,
210+
},
211+
BSONPtrTracker: nil,
212+
},
213+
data: docToBytes(D{
214+
{Key: "bv_tracker", Value: primitive.MinKey{}},
215+
{Key: "bv_ptr_tracker", Value: primitive.MinKey{}},
216+
{Key: "b_tracker", Value: primitive.MinKey{}},
217+
{Key: "b_ptr_tracker", Value: primitive.MinKey{}},
218+
}),
219+
},
220+
{
221+
name: "nil pointer and non-pointer type with BSON maxkey",
222+
sType: reflect.TypeOf(unmarshalBehaviorTestCase{}),
223+
want: &unmarshalBehaviorTestCase{
224+
BSONValueTracker: unmarshalBSONValueCallTracker{
225+
called: true,
226+
},
227+
BSONValuePtrTracker: &unmarshalBSONValueCallTracker{
228+
called: true,
229+
},
230+
BSONTracker: unmarshalBSONCallTracker{
231+
called: true,
232+
},
233+
BSONPtrTracker: nil,
234+
},
235+
data: docToBytes(D{
236+
{Key: "bv_tracker", Value: primitive.MaxKey{}},
237+
{Key: "bv_ptr_tracker", Value: primitive.MaxKey{}},
238+
{Key: "b_tracker", Value: primitive.MaxKey{}},
239+
{Key: "b_ptr_tracker", Value: primitive.MaxKey{}},
240+
}),
241+
},
197242
}
198243
}
199244

0 commit comments

Comments
 (0)