package main import ( "encoding/json" "fmt" "reflect" ) type Something interface{} type Something1 struct { Aaa, Bbb string } type Something2 struct { Ccc, Ddd string } var _ Something = (*Something1)(nil) var _ Something = (*Something2)(nil) func UnmarshalCustomValue(data []byte, typeJsonField, valueJsonField string, customTypes map[string]reflect.Type) (interface{}, error) { m := map[string]interface{}{} if err := json.Unmarshal(data, &m); err != nil { return nil, err } typeName := m[typeJsonField].(string) var value Something if ty, found := customTypes[typeName]; found { value = reflect.New(ty).Interface().(Something) } valueBytes, err := json.Marshal(m[valueJsonField]) if err != nil { return nil, err } err = json.Unmarshal(valueBytes, &value) if err != nil { return nil, err } return value, nil } type Container struct { Type string `json:"type"` Value Something `json:"value"` } func (c *Container) UnmarshalJSON(data []byte) error { value, err := UnmarshalCustomValue(data, "type", "value", map[string]reflect.Type{ "something1": reflect.TypeOf(Something1{}), "something2": reflect.TypeOf(Something2{}), }) if err != nil { return err } c.Value = value return nil } var _ json.Unmarshaler = (*Container)(nil) func panicIfErr(err error) { if err != nil { panic(err.Error()) } } func main() { testUnmarshalling(`{"type":"something1","value":{"Aaa": "a"}}`) testUnmarshalling(`{"type":"something2","value":{"Ccc": "a"}}`) } func testUnmarshalling(jsonStr string) { var container Container err := json.Unmarshal([]byte(jsonStr), &container) panicIfErr(err) fmt.Printf("container=%+v\n", container) fmt.Printf("value=%#v\n", container.Value) }