Skip to content
This repository was archived by the owner on Jul 22, 2024. It is now read-only.

Commit 18a713d

Browse files
authored
Merge pull request #232 from mitchellh/issue-231
decodeMapFromStruct: Only deref element if we're squashing the struct
2 parents 1b4332d + cbfe794 commit 18a713d

File tree

3 files changed

+46
-26
lines changed

3 files changed

+46
-26
lines changed

mapstructure.go

+11-6
Original file line numberDiff line numberDiff line change
@@ -894,10 +894,6 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
894894
// Next get the actual value of this field and verify it is assignable
895895
// to the map value.
896896
v := dataVal.Field(i)
897-
if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct {
898-
// Handle embedded struct pointers as embedded structs.
899-
v = v.Elem()
900-
}
901897
if !v.Type().AssignableTo(valMap.Type().Elem()) {
902898
return fmt.Errorf("cannot assign type '%s' to map value field of type '%s'", v.Type(), valMap.Type().Elem())
903899
}
@@ -907,6 +903,7 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
907903

908904
// If Squash is set in the config, we squash the field down.
909905
squash := d.config.Squash && v.Kind() == reflect.Struct && f.Anonymous
906+
910907
// Determine the name of the key in the map
911908
if index := strings.Index(tagValue, ","); index != -1 {
912909
if tagValue[:index] == "-" {
@@ -919,8 +916,16 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
919916

920917
// If "squash" is specified in the tag, we squash the field down.
921918
squash = !squash && strings.Index(tagValue[index+1:], "squash") != -1
922-
if squash && v.Kind() != reflect.Struct {
923-
return fmt.Errorf("cannot squash non-struct type '%s'", v.Type())
919+
if squash {
920+
// When squashing, the embedded type can be a pointer to a struct.
921+
if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct {
922+
v = v.Elem()
923+
}
924+
925+
// The final type must be a struct
926+
if v.Kind() != reflect.Struct {
927+
return fmt.Errorf("cannot squash non-struct type '%s'", v.Type())
928+
}
924929
}
925930
keyName = tagValue[:index]
926931
} else if len(tagValue) > 0 {

mapstructure_bugs_test.go

+34
Original file line numberDiff line numberDiff line change
@@ -567,3 +567,37 @@ func TestDecode_weakEmptyStringToInt(t *testing.T) {
567567
t.Errorf("expected \n%#v, got: \n%#v", expectedResultWeak, resultWeak)
568568
}
569569
}
570+
571+
// GH-228: Squash cause *time.Time set to zero
572+
func TestMapSquash(t *testing.T) {
573+
type AA struct {
574+
T *time.Time
575+
}
576+
type A struct {
577+
AA
578+
}
579+
580+
v := time.Now()
581+
in := &AA{
582+
T: &v,
583+
}
584+
out := &A{}
585+
d, err := NewDecoder(&DecoderConfig{
586+
Squash: true,
587+
Result: out,
588+
})
589+
if err != nil {
590+
t.Fatalf("err: %s", err)
591+
}
592+
if err := d.Decode(in); err != nil {
593+
t.Fatalf("err: %s", err)
594+
}
595+
596+
// these failed
597+
if !v.Equal(*out.T) {
598+
t.Fatal("expected equal")
599+
}
600+
if out.T.IsZero() {
601+
t.Fatal("expected false")
602+
}
603+
}

mapstructure_test.go

+1-20
Original file line numberDiff line numberDiff line change
@@ -2390,26 +2390,7 @@ func TestDecode_StructTaggedWithOmitempty_KeepNonEmptyValues(t *testing.T) {
23902390
"visible-map": emptyMap,
23912391
"omittable-map": map[string]interface{}{"k": "v"},
23922392
"visible-nested": emptyNested,
2393-
"omittable-nested": map[string]interface{}{
2394-
"Vbar": map[string]interface{}{
2395-
"Vbool": false,
2396-
"Vdata": interface{}(nil),
2397-
"Vextra": "",
2398-
"Vfloat": float64(0),
2399-
"Vint": 0,
2400-
"Vint16": int16(0),
2401-
"Vint32": int32(0),
2402-
"Vint64": int64(0),
2403-
"Vint8": int8(0),
2404-
"VjsonFloat": float64(0),
2405-
"VjsonInt": 0,
2406-
"VjsonNumber": json.Number(""),
2407-
"VjsonUint": uint(0),
2408-
"Vstring": "",
2409-
"Vuint": uint(0),
2410-
},
2411-
"Vfoo": "",
2412-
},
2393+
"omittable-nested": &Nested{},
24132394
}
24142395

24152396
actual := &map[string]interface{}{}

0 commit comments

Comments
 (0)