Flattening marshalled JSON structs with anonymous members in Go

前端 未结 7 1994
感情败类
感情败类 2021-01-02 10:20

Given the following code: (reproduced here at play.golang.org.)

package main

import (
    "encoding/json"
    "fmt"
)

type User struct {         


        
7条回答
  •  情书的邮戳
    2021-01-02 11:08

    Working playground link: http://play.golang.org/p/_r-bQIw347

    The gist of it is this; by using the reflect package we loop over the fields of the struct we wish to serialize and map them to a map[string]interface{} we can now retain the flat structure of the original struct without introducing new fields.

    Caveat emptor, there should probably be several checks against some of the assumptions made in this code. For instance it assumes that MarshalHateoas always receives pointers to values.

    package main
    
    import (
        "encoding/json"
        "fmt"
        "reflect"
    )
    
    type User struct {
        Id   int    `json:"id"`
        Name string `json:"name"`
    }
    
    type Session struct {
        Id     int `json:"id"`
        UserId int `json:"userId"`
    }
    
    func MarshalHateoas(subject interface{}) ([]byte, error) {
        links := make(map[string]string)
        out := make(map[string]interface{})
        subjectValue := reflect.Indirect(reflect.ValueOf(subject))
        subjectType := subjectValue.Type()
        for i := 0; i < subjectType.NumField(); i++ {
            field := subjectType.Field(i)
            name := subjectType.Field(i).Name
            out[field.Tag.Get("json")] = subjectValue.FieldByName(name).Interface()
        }
        switch s := subject.(type) {
        case *User:
            links["self"] = fmt.Sprintf("http://user/%d", s.Id)
        case *Session:
            links["self"] = fmt.Sprintf("http://session/%d", s.Id)
        }
        out["_links"] = links
        return json.MarshalIndent(out, "", "    ")
    }
    func main() {
        u := &User{123, "James Dean"}
        s := &Session{456, 123}
        json, err := MarshalHateoas(u)
        if err != nil {
            panic(err)
        } else {
            fmt.Println("User JSON:")
            fmt.Println(string(json))
        }
        json, err = MarshalHateoas(s)
        if err != nil {
            panic(err)
        } else {
            fmt.Println("Session JSON:")
            fmt.Println(string(json))
        }
    }
    

提交回复
热议问题