简体   繁体   English

将 json 解组为反射结构

[英]Unmarshal json to reflected struct

Is it possible to unmarshal JSON into a struct made from reflection without hardcoding the original type?是否可以在不硬编码原始类型的情况下将 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)
}

I used a cast to Employee in this example.在此示例中,我使用了对Employee的强制转换。 But what if i don't know the type?但是如果我不知道类型怎么办?

When i just use v for the unmarhaling the struct will be zeroed.当我只使用v进行解组时,结构将被清零。

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

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. 推断new具有interface{}类型。

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

You can avoid the type assertion if instead of getting the Elem() you work directly with the pointer reference. 如果不是让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)
}

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

If you don't know the type at all, you can Unmarshal the JSON string into an interface{}. 如果您根本不知道类型,则可以将JSON字符串解组为接口{}。 If you then need to work with the Unmarshaled data, you can convert it to the desired type. 如果您需要使用Unmarshaled数据,则可以将其转换为所需类型。

Here's an example: 这是一个例子:

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

You can check it on the Go Playground . 您可以在Go Playground查看


// https://github.com/xiaojun207/go-base-utils/blob/master/utils/Clone.go
func NewInterface(typ reflect.Type, data []byte) interface{} {
    if typ.Kind() == reflect.Ptr {
        typ = typ.Elem()
        dst := reflect.New(typ).Elem()
        json.Unmarshal(data, dst.Addr().Interface())
        return dst.Addr().Interface()
    }else {
        dst := reflect.New(typ).Elem()
        json.Unmarshal(data, dst.Addr().Interface())
        return dst.Interface()
    }
}

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

func main() {
    data := "{\"firstName\": \"John\"}"
    obj := NewInterface(reflect.TypeOf(Employee{}), []byte(data))
    fmt.Println("Employee:", obj)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM