解组json以反映结构

时间:2017-08-14 16:57:40

标签: json go reflection unmarshalling

是否可以将JSON解组为由反射构成的结构而无需对原始类型进行硬编码?

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)
}

在这个例子中,我使用了强制转换为Employee。但如果我不知道这种类型怎么办?

当我只使用v进行解组时,结构将被清零。

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

当我省略演员表时,我会得到一张地图。这是可以理解的

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

2 个答案:

答案 0 :(得分:7)

这里的问题是,如果省略这里的类型断言:

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

推断new具有interface{}类型。

然后当你取消地址解组时,&new的类型是*interface{}(指向接口{}的指针)和unmarshal不能按预期工作。

您可以避免使用类型断言,而不是让Elem()直接使用指针引用。

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)
}

游乐场:https://play.golang.org/p/lTBU-1PqM4

答案 1 :(得分:0)

如果您根本不知道类型,可以将JSON字符串解组为接口{}。如果您需要使用Unmarshaled数据,则可以将其转换为所需类型。

以下是一个例子:

package main

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

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

func deserialize(jsonData string) interface{} {
    var obj interface{}

    if err := json.Unmarshal([]byte(jsonData), &obj); err != nil {
        panic(err)
    }

    return obj
}

func NewEmployee(objData map[string]interface{}) *Employee {
    s := (*Employee)(nil)
    t := reflect.TypeOf(s).Elem()
    employeePtr := reflect.New(t)
    employee := (*Employee)(unsafe.Pointer(employeePtr.Pointer()))
    employee.Firstname = objData["firstName"].(string)

    return employee
}

func main() {
    jsonData := "{\"firstName\": \"John\"}"

    obj := deserialize(jsonData)

    objData := obj.(map[string]interface{})
    employee := NewEmployee(objData)

    fmt.Printf("%s\n", employee.Firstname)
}

您可以在Go Playground上查看。