[GODRIVER-1414] Can't marshal nil pointer of structure with custom MarshalBSONValue? Created: 20/Nov/19  Updated: 27/Oct/23  Resolved: 20/Nov/19

Status: Closed
Project: Go Driver
Component/s: BSON
Affects Version/s: 1.1.3
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: n f Assignee: Unassigned
Resolution: Works as Designed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

mongo-go-driver 1.1.3 and latest version from github
Go 1.12.7
MacOS Catalina



 Description   

// code placeholder
package main
 
import (
    "fmt"
    "github.com/pkg/errors"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/bson/bsontype"
    "go.mongodb.org/mongo-driver/x/bsonx"
    "go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
    "log"
    "strconv"
)
 
type Bar struct {
    a int64
}
 
func (b Bar) MarshalBSONValue() (bsontype.Type, []byte, error) {
    return bsonx.String(fmt.Sprintf("%d", b.a)).MarshalBSONValue()
}
 
func (b *Bar) UnmarshalBSONValue(t bsontype.Type, data []byte) error {
    if t != bsontype.String {
        return errors.Errorf("bsontype(%s) not allowed in Bar.UnmarshalBSONValue, only string accept", t.String())
    }
    str, _, ok := bsoncore.ReadString(data)
    if !ok {
        return errors.Errorf("decode string, but string not found")
    }
 
    dec, err := strconv.ParseInt(str, 10, 64)
    if err != nil {
        return err
    }
    *b = Bar{a:dec}
    return nil
}
 
type Foo struct {
    Bar *Bar`bson:"Bar, omitempty"`
}
 
func main() {
    f := Foo{}
    _, err := bson.Marshal(f)
    if err != nil {
        log.Fatalf("Failed to marshal. Error: %v", err)
    }
}

 

 

this program will panic with error:
 
{{panic: value method main.Bar.MarshalBSONValue called using nil *Bar pointer

goroutine 1 [running]:main.(*Bar).MarshalBSONValue(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)<autogenerated>:1 +0x87reflect.Value.call(0x11ebc60, 0xc000010330, 0x293, 0x1218915, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, ...)/usr/local/go/src/reflect/value.go:447 +0x461}}



 Comments   
Comment by Divjot Arora (Inactive) [ 20/Nov/19 ]

Hi niffler@foxmail.com,

Thank you for your report and repro. As you mentioned in the comment, removing the space before omitempty fixes the issue and results in the Bar field not being serialized at all. As an FYI, if you did want to serialize the Bar field as BSON null (e.g. the resulting document would be {Bar: null}, you could implement MarshalBSONValue on *Bar rather than Bar as follows:

func (b *Bar) MarshalBSONValue() (bsontype.Type, []byte, error) {
    if b == nil {
        return bsonx.Null().MarshalBSONValue()
    }
    return bsonx.String(fmt.Sprintf("%d", b.a)).MarshalBSONValue()
}

As this issue is resolved, I'm going to close this ticket. Feel free to comment on the ticket again or open another ticket if you have any other issues.

Comment by n f [ 20/Nov/19 ]

Sorry, it's omitempty syntax error, there is a space between ·Bar,· and ·omitempty· in the code, it shouldn't be there

Generated at Thu Feb 08 08:36:21 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.