Minty
Minty

Reputation: 1241

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.

Upvotes: 5

Views: 7007

Answers (2)

Nick Craig-Wood
Nick Craig-Wood

Reputation: 54089

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!

Upvotes: 5

Jeremy Wall
Jeremy Wall

Reputation: 25237

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.

Upvotes: 1

Related Questions