Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unmarshal on reflected value

Here is the code

package main

import (
    "fmt"

    "encoding/json"
    "reflect"
)

var (
    datajson []byte
    //ref mapp
)

type mapp map[string]reflect.Type

type User struct {
    Name string
    //Type map[string]reflect.Type
}

func MustJSONEncode(i interface{}) []byte {
    result, err := json.Marshal(i)
    if err != nil {
        panic(err)
    }
    return result
}
func MustJSONDecode(b []byte, i interface{}) {
    err := json.Unmarshal(b, i)
    if err != nil {
        panic(err)
    }

}
func Store(a interface{}) {
    datajson = MustJSONEncode(a)
    //fmt.Println(datajson)
}

func Get(a []byte, b interface{}) {
    objType := reflect.TypeOf(b).Elem()
obj := reflect.New(objType)
//fmt.Println(obj)
MustJSONDecode(a, &obj)
fmt.Printf("%s", obj)
    }

func main() {

    dummy := &User{}
    david := User{Name: "DavidMahon"}

    Store(david)
    Get(datajson, dummy)

}

In the Get function

func Get(a []byte, b interface{}) {
    objType := reflect.TypeOf(b).Elem()
obj := reflect.New(objType)
//fmt.Println(obj)
MustJSONDecode(a, &obj)
fmt.Printf("%s", obj)
    }

I am unable to unmarshal the json into the underlying object type.

Whats wrong here? I am so stuck here. Something very simple yet so difficult to figure out.

Thanks

UPDATE::Goal of this problem is to retreive a fully formed object of type passed in Get function.

The approach mentioned by Nick on the comment below doesnot get me the actual object which I already tried before. I can anyways retrieve the data (even when the object has recursive objects underneath) in a map like this

func Get(a []byte) {
    var f interface{}

    //buf := bytes.NewBuffer(a)
    //v := buf.String()
    //usr := &User{}

    MustJSONDecode(a, &f)
    fmt.Printf("\n %v \n", f)
}

However I need the actual object back not just the data. Something like user := &User{"SomeName"} where I need user object back from Unmarshall. The trick is somewhere in reflection but dont know how.

like image 603
Minty Avatar asked Aug 17 '13 23:08

Minty


2 Answers

I'm confused as to why you want to do this, but here is how to fix it

func Get(a []byte, b interface{}) {
    objType := reflect.TypeOf(b).Elem()
    obj := reflect.New(objType).Interface()
    //fmt.Println(obj)
    MustJSONDecode(a, &obj)
    fmt.Printf("obj = %#v\n", obj)
}

Note the call to Interface().

Playground link

It seems to me that you are going to a lot of trouble to make an empty &User when you already have one in b, eg

func Get(a []byte, b interface{}) {
    MustJSONDecode(a, &b)
    fmt.Printf("obj = %#v\n", b)
}

But I'm guessing there is some more to this plan which isn't apparent here!

like image 149
Nick Craig-Wood Avatar answered Nov 14 '22 08:11

Nick Craig-Wood


reflect.New(objType) returns a reflect.Value Which is not the thing as the interface you passed. According to the docs for Value It is a struct with only unexported fields. the json package can't work with unexported fields. Since it's not the same object as you passed in and it's not even json encodable/decodable the json package will fail.

You will probably find the Laws of Reflection article useful while trying to use the reflect package.

like image 31
Jeremy Wall Avatar answered Nov 14 '22 08:11

Jeremy Wall