returning untyped nil from decode hook will assign properly to interface
diff --git a/decode_hooks.go b/decode_hooks.go index aa91f76..115ae67 100644 --- a/decode_hooks.go +++ b/decode_hooks.go
@@ -72,7 +72,10 @@ } // Modify the from kind to be correct with the new data - f = reflect.ValueOf(data).Type() + f = nil + if val := reflect.ValueOf(data); val.IsValid() { + f = val.Type() + } } return data, nil
diff --git a/mapstructure.go b/mapstructure.go index a367a95..4490521 100644 --- a/mapstructure.go +++ b/mapstructure.go
@@ -246,6 +246,10 @@ // value to "data" of that type. func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error { dataVal := reflect.ValueOf(data) + if !dataVal.IsValid() { + dataVal = reflect.Zero(val.Type()) + } + dataValType := dataVal.Type() if !dataValType.AssignableTo(val.Type()) { return fmt.Errorf(
diff --git a/mapstructure_test.go b/mapstructure_test.go index 45e7284..4d40ace 100644 --- a/mapstructure_test.go +++ b/mapstructure_test.go
@@ -1,6 +1,7 @@ package mapstructure import ( + "io" "reflect" "sort" "strings" @@ -60,6 +61,10 @@ Vbar *Basic } +type NilInterface struct { + W io.Writer +} + type Slice struct { Vfoo string Vbar []string @@ -382,6 +387,42 @@ } } +func TestDecode_NilInterfaceHook(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "w": "", + } + + decodeHook := func(f, t reflect.Type, v interface{}) (interface{}, error) { + if t.String() == "io.Writer" { + return nil, nil + } + + return v, nil + } + + var result NilInterface + config := &DecoderConfig{ + DecodeHook: decodeHook, + Result: &result, + } + + decoder, err := NewDecoder(config) + if err != nil { + t.Fatalf("err: %s", err) + } + + err = decoder.Decode(input) + if err != nil { + t.Fatalf("got an err: %s", err) + } + + if result.W != nil { + t.Errorf("W should be nil: %#v", result.W) + } +} + func TestDecode_NonStruct(t *testing.T) { t.Parallel()