I have an object of type foo containing an interface ActivationInterface ; this object is persisted and I have trouble fetching it back, as the underlying type of the inner object is not known.
I implemented UnmarshalBSON as follow without success ; it seems that even after setting the concrete type of the interface, the unmarshaler still does now the underlying type and I still get the error: error decoding key act: no decoder found for main.ActivationInterface
Hey Jack, thanks for the help. It does not seem relevant as I think the problem is not the same. In my case, there is a difference of behavior between BSON and JSON when I recursively Unmarshal ; on the 2nd call, the type that I defined during the 1rst call for the interface, doesn’t seem to be set, as I still get an error.
It is not about having fields inlined
Thanks !
I believe the root cause is that the Go driver BSON unmarshal logic doesn’t consider the value assigned to a struct field, only the type in the struct definition (e.g. Activation1 vs interface{}). I’ve created GODRIVER-2382 that describes the unexpected behavior vs the Go "encoding/json" behavior.
In the meantime, consider converting the data into a bson.Raw so you can look up the fields individually and unmarshal that way:
func (q *foo) UnmarshalBSON(data []byte) error {
raw := bson.Raw(data)
// Lookup the "type" value to figure out which activation
// type to unmarshal.
t, ok := raw.Lookup("type").StringValueOK()
if !ok {
return errors.New(`failed to find field "type"`)
}
q.Type = t
// Lookup the "act" value as bytes so we can unmarshal it
// into the correct activation type.
actVal := raw.Lookup("act").Value
if len(actVal) == 0 {
return errors.New(`failed to find field "act"`)
}
switch t {
case "act1":
q.Act = new(Activation1)
case "act2":
q.Act = new(Activation2)
default:
return fmt.Errorf("unknown type %q", t)
}
return bson.Unmarshal(actVal, q.Act)
}
Check out the code integrated into your original example here.
Thanks a lot for your help.
You indeed did put better words than mine on the unwanted behavior, thanks for filling the Jira ticket !
Your solution is the one I implemented to have my code working waiting for a more elegant way. As you can imagine, the example code I provided is not whole ; in the reality, foo contains more than 20 props that I copy one by one from a temporary type (used to replace the interface{} by Raw). That works but is ugly ;D
Thanks again, should I close this thread as solved and wait for the Jira ticket to be updated ?
Best regards,