diff --git a/mapstructure.go b/mapstructure.go index 7581806a..52623e59 100644 --- a/mapstructure.go +++ b/mapstructure.go @@ -453,6 +453,13 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e return nil } + if outVal.CanAddr() { + v := outVal.Addr() + if u, ok := v.Interface().(decoder); ok { + return u.DecodeMapstructure(input) + } + } + if d.config.DecodeHook != nil { // We have a DecodeHook, so let's pre-process the input. var err error @@ -1540,3 +1547,7 @@ func dereferencePtrToStructIfNeeded(v reflect.Value, tagName string) reflect.Val } return v } + +type decoder interface { + DecodeMapstructure(interface{}) error +} diff --git a/mapstructure_examples_test.go b/mapstructure_examples_test.go index 2413b694..915cbe8c 100644 --- a/mapstructure_examples_test.go +++ b/mapstructure_examples_test.go @@ -254,3 +254,32 @@ func ExampleDecode_omitempty() { // Output: // &map[Age:0 FirstName:Somebody] } + +type Someone struct { + Name string +} + +func (p *Someone) DecodeMapstructure(v interface{}) error { + if name, ok := v.(string); ok { + p.Name = name + return nil + } + return fmt.Errorf("undecipherable name") +} + +func ExampleDecode_custom_decoder_type() { + type Profile struct { + Friends []Someone + } + input := map[string]interface{}{ + "friends": []string{"Mitchell"}, + } + var result Profile + err := Decode(input, &result) + if err != nil { + panic(err) + } + fmt.Printf("%#v", result) + // Output: + // mapstructure.Profile{Friends:[]mapstructure.Someone{mapstructure.Someone{Name:"Mitchell"}}} +}