mapstructure icon indicating copy to clipboard operation
mapstructure copied to clipboard

Wrong target type restriction when decoding struct to map

Open mullerch opened this issue 2 years ago • 1 comments

When the target map to decode the result to is strongly typed, the decoding process fails, even if the map type matches the source structure.

func TestDecode_structToTypedMap(t *testing.T) {
	type SourceChild struct {
		String string `mapstructure:"string"`
	}

	type SourceParent struct {
		Child SourceChild `mapstructure:"child"`
	}

	var target map[string]map[string]interface{} // This is the reason the test fails
	//var target map[string]interface{} // With this variant it works

	source := SourceParent{
		Child: SourceChild{
			String: "hello",
		},
	}

	if err := Decode(source, &target); err != nil {
		t.Fatalf("got error: %s", err)
	}

	expected := map[string]interface{}{
		"child": map[string]interface{}{
			"string": "hello",
		},
	}

	if !reflect.DeepEqual(target, expected) {
		t.Fatalf("bad: \nexpected: %#v\nresult: %#v", expected, target)
	}
}

Produces:

=== RUN   TestDecode_structToTypedMap
    mapstructure_test.go:2884: got error: cannot assign type 'mapstructure.SourceChild' to map value field of type 'map[string]interface {}'
--- FAIL: TestDecode_structToTypedMap (0.00s)

As the target sutructure matches the needs of the decoding process, I would expect this to work.

mapstructure version bf980b35cac4dfd34e05254ee5aba086504c3f96 go version go1.18.7 linux/amd64

mullerch avatar Oct 27 '22 06:10 mullerch

As far as I understand, the issue is here : https://github.com/mitchellh/mapstructure/blob/main/mapstructure.go#L976

The type of the map field is not the same as the parent (owning) map. This only works if the type is generic (interface{}).

mullerch avatar Oct 31 '22 13:10 mullerch