globalsign / mgo

The MongoDB driver for Go
Other
1.97k stars 230 forks source link

bson.Marshal does not support embedding of private structs #238

Closed CylusFaranIdo closed 5 years ago

CylusFaranIdo commented 6 years ago

When trying to marshal struct with embedded private struct - bson.Marshal fail with the following error: "error: reflect.Value.Interface: cannot return value obtained from unexported field or method".

The expected behavior is to marshal all exported fields of the embedded struct. This is what json.Marshal do in this case.

The source of the bug is located in the file "encode.go" in line 509. calling v.Interface() on unexported struct creates panic.

A Code example that demonstrates the bug:

package main

import (
    "encoding/json"
    "fmt"

    "github.com/globalsign/mgo/bson"
)

type test struct {
    b
}

type b struct {
    ValueInB        uint32
    privateValueInB uint32
}

func main() {
    x := test{b: b{ValueInB: 7, privateValueInB: 8}}

    y, err := bson.Marshal(x)
    if err != nil {
        fmt.Printf("bson.Marshal error : %+v\n", err)
    }

    fmt.Printf("marshaled bson: %v\n", y)

    z, err := json.Marshal(x)
    if err != nil {
        fmt.Printf("bson.Marshal error : %+v\n", err)
    }

    fmt.Printf("marshaled JSON: %v\n", z)
}

Output:

bson.Marshal error : reflect.Value.Interface: cannot return value obtained from unexported field or method marshaled bson: [] marshaled JSON: [123 34 86 97 108 117 101 73 110 66 34 58 55 125]

maitesin commented 6 years ago

Hi @CylusFaranIdo ,

Thanks for reporting this! You are right, it should follow the same behaviour of the json.Mashal.

I will have a look at the problem as soon as I can, however we will happily accept a PR since you already know where the problem is!

Oscar

chenjie4255 commented 5 years ago

@CylusFaranIdo @maitesin

try add bson:",inline" and see if this is what you want?

package main

import (
    "encoding/json"
    "fmt"

    "github.com/globalsign/mgo/bson"
)

type test struct {
    b `bson:",inline"`
}

type b struct {
    ValueInB        uint32
    privateValueInB uint32
}

func main() {
    x := test{b: b{ValueInB: 7, privateValueInB: 8}}

    y, err := bson.Marshal(x)
    if err != nil {
        fmt.Printf("bson.Marshal error : %+v\n", err)
    }

    fmt.Printf("marshaled bson: %v\n", y)

    z, err := json.Marshal(x)
    if err != nil {
        fmt.Printf("bson.Marshal error : %+v\n", err)
    }

    fmt.Printf("marshaled JSON: %v\n", z)
}

output:

marshaled bson: [19 0 0 0 16 118 97 108 117 101 105 110 98 0 7 0 0 0 0]
marshaled JSON: [123 34 86 97 108 117 101 73 110 66 34 58 55 125]
domodwyer commented 5 years ago

Hi @CylusFaranIdo

@chenjie4255 is correct! Thanks :)

I'm going to close this as it is intended behaviour, not a bug.

Dom