JSON decode a map[string]interface{} into a struct containing custom type gives Error

My app takes a JSON string, unmarshal into a struct BiggerType and then, decode the struct’s field Settings into a type MainType. BiggerType needs to support multiple types of Settings and hence, is and has to be declared as map[string]interface{}. The app used to be working fine until we have a new type of Settings, i.e. MainType containing some custom fields with the type SpecialType.

The structs and the main codes are included below. Running the code gives the following error.

* 'b' expected a map, got 'string'

Some codes were removed for brevity

package main

import (
	...
	"github.com/mitchellh/mapstructure"
)

const myJSON = `{
  "settings": {
    "a": {
      "aa": {
        "aaa": {
          "sta": "special_object_A",
          "stb": "special_object_B"
        },
        "aab": "bab"
      },
      "ab": true
    },
    "b": "special_string"
  },
  "other": "other"
}`

func main() {
	var biggerType BiggerType

	err := json.Unmarshal([]byte(myJSON), &biggerType)
	if err != nil {
		panic(err)
	}

	var decodedMainType MainType

	if err := mapstructure.Decode(biggerType.Settings, &decodedMainType); err != nil {
		panic(err)
	}
}

type BiggerType struct {
	Other    string   `json:"other"`
	// Settings MainType `json:"settings"` can't be used as it needs to support other "Settings"
	Settings map[string]interface{} `json:"settings"`
}

type A struct {
	Aa *AA   `json:"aa"`
	Ab *bool `json:"ab"`
}

type AA struct {
	Aaa SpecialType `json:"aaa"`
	Aab string      `json:"aab"`
}

type MainType struct {
	A A           `json:"a"`
	B SpecialType `json:"b"`
}

type SpecialTypeObject struct {
	Sta string `json:"sta"`
	Stb string `json:"stb"`
}

func (s SpecialTypeObject) InterfaceMethod() (string, error) {
	return s.Sta + "+" + s.Stb, nil
}

type SpecialTypeString string

func (s SpecialTypeString) InterfaceMethod() (string, error) {
	return string(s), nil
}

type SpecialInterface interface {
	InterfaceMethod() (string, error)
}

// SpecialType SpecialTypeString | SpecialTypeObject
type SpecialType struct {
	Value SpecialInterface
}

func (s *SpecialType) UnmarshalJSON(data []byte) error {
	...
}

My goal is to be able to decode biggerType.Settings into decodedMainType with all the values intact. Can anyone please share with me any workaround or/and suggestions?

The playground to replicate the issue: Go Playground - The Go Programming Language

Thank you.

I tried a workaround to marshal biggerType.Settings to []byte first then unmarshal, it works, here is the code Go Playground - The Go Programming Language
or probably using json.Encoder and json.Decoder makes more sense?

Thanks. Your solution works. I think the custom decoder/encoder would work.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.