Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unmarshal json to reflected struct

Is it possible to unmarshal JSON into a struct made from reflection without hardcoding the original type?

package main

import (
  "fmt"
  "encoding/json"
  "reflect"
)

type Employee struct {
  Firstname string     `json:"firstname"`
}

func main() {
  //Original struct
  orig := new(Employee)

  t := reflect.TypeOf(orig)
  v := reflect.New(t.Elem())

  //Reflected struct
  new := v.Elem().Interface().(Employee)

  // Unmarshal to reflected struct
  json.Unmarshal([]byte("{\"firstname\": \"bender\"}"), &new)

  fmt.Printf("%+v\n", new)
}

I used a cast to Employee in this example. But what if i don't know the type?

When i just use v for the unmarhaling the struct will be zeroed.

json.Unmarshal([]byte("{\"firstname\": \"bender\"}"), v)

When I omit the cast I get a map. which is understandable

json.Unmarshal([]byte("{\"firstname\": \"bender\"}"), v.Elem().Interface())
like image 866
Slemgrim Avatar asked Aug 14 '17 16:08

Slemgrim


1 Answers

The problem here is that if you omit the type assertion here:

new := v.Elem().Interface()

The new is inferred to have a interface{} type.

Then when you take the address to unmarshal, the type of &new is *interface{} (pointer to interface{}) and unmarshal does not work as you expect.

You can avoid the type assertion if instead of getting the Elem() you work directly with the pointer reference.

func main() {
  //Original struct
  orig := new(Employee)

  t := reflect.TypeOf(orig)
  v := reflect.New(t.Elem())

  // reflected pointer
  newP := v.Interface()

  // Unmarshal to reflected struct pointer
  json.Unmarshal([]byte("{\"firstname\": \"bender\"}"), newP)

  fmt.Printf("%+v\n", newP)
}

Playground: https://play.golang.org/p/lTBU-1PqM4

like image 154
eugenioy Avatar answered Oct 14 '22 16:10

eugenioy