Skip to content

Instantly share code, notes, and snippets.

@cghiban
Forked from tkrajina/unmarshal_interface.go
Created March 24, 2025 01:02
Show Gist options
  • Save cghiban/45666d13613e78f16cbe83eb213fb108 to your computer and use it in GitHub Desktop.
Save cghiban/45666d13613e78f16cbe83eb213fb108 to your computer and use it in GitHub Desktop.

Revisions

  1. @tkrajina tkrajina revised this gist Feb 4, 2017. 1 changed file with 20 additions and 21 deletions.
    41 changes: 20 additions & 21 deletions unmarshal_interface.go
    Original file line number Diff line number Diff line change
    @@ -19,6 +19,25 @@ type Something2 struct {
    var _ Something = (*Something1)(nil)
    var _ Something = (*Something2)(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
    }

    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 {
    @@ -36,33 +55,13 @@ func UnmarshalCustomValue(data []byte, typeJsonField, valueJsonField string, cus
    return nil, err
    }

    err = json.Unmarshal(valueBytes, &value)
    if err != nil {
    if err = json.Unmarshal(valueBytes, &value); 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) {
  2. @tkrajina tkrajina revised this gist Feb 4, 2017. 1 changed file with 23 additions and 16 deletions.
    39 changes: 23 additions & 16 deletions unmarshal_interface.go
    Original file line number Diff line number Diff line change
    @@ -19,34 +19,41 @@ type Something2 struct {
    var _ Something = (*Something1)(nil)
    var _ Something = (*Something2)(nil)

    var somethingTypes = map[string]reflect.Type{
    "something1": reflect.TypeOf(Something1{}),
    "something2": reflect.TypeOf(Something2{}),
    }

    type Container struct {
    Type string `json:"type"`
    Value Something `json:"value"`
    }

    func (c *Container) UnmarshalJSON(data []byte) error {
    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 err
    return nil, err
    }

    typeName := m["type"].(string)
    typeName := m[typeJsonField].(string)
    var value Something
    if ty, found := somethingTypes[typeName]; found {
    if ty, found := customTypes[typeName]; found {
    value = reflect.New(ty).Interface().(Something)
    }

    valueBytes, err := json.Marshal(m["value"])
    valueBytes, err := json.Marshal(m[valueJsonField])
    if err != nil {
    return err
    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
    }
  3. @tkrajina tkrajina revised this gist Feb 4, 2017. No changes.
  4. @tkrajina tkrajina created this gist Feb 4, 2017.
    78 changes: 78 additions & 0 deletions unmarshal_interface.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,78 @@
    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)

    var somethingTypes = map[string]reflect.Type{
    "something1": reflect.TypeOf(Something1{}),
    "something2": reflect.TypeOf(Something2{}),
    }

    type Container struct {
    Type string `json:"type"`
    Value Something `json:"value"`
    }

    func (c *Container) UnmarshalJSON(data []byte) error {
    m := map[string]interface{}{}
    if err := json.Unmarshal(data, &m); err != nil {
    return err
    }

    typeName := m["type"].(string)
    var value Something
    if ty, found := somethingTypes[typeName]; found {
    value = reflect.New(ty).Interface().(Something)
    }

    valueBytes, err := json.Marshal(m["value"])
    if err != nil {
    return err
    }

    err = json.Unmarshal(valueBytes, &value)
    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)
    }