Lee*_*ley 7 json marshalling go
鉴于以下代码:( 转载于此处play.golang.org)
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Id int `json:"id"`
Name string `json:"name"`
}
type Session struct {
Id int `json:"id"`
UserId int `json:"userId"`
}
type Anything interface{}
type Hateoas struct {
Anything
Links map[string]string `json:"_links"`
}
func MarshalHateoas(subject interface{}) ([]byte, error) {
h := &Hateoas{subject, make(map[string]string)}
switch s := subject.(type) {
case *User:
h.Links["self"] = fmt.Sprintf("http://user/%d", s.Id)
case *Session:
h.Links["self"] = fmt.Sprintf("http://session/%d", s.Id)
}
return json.MarshalIndent(h, "", " ")
}
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))
}
}
Run Code Online (Sandbox Code Playgroud)
我试图让渲染的JSON 在我的情况下看起来正确,这意味着:
User JSON:
{
"id": 123,
"name": "James Dean",
"_links": {
"self": "http://user/123"
}
}
Session JSON:
{
"id": 456,
"userId": 123,
"_links": {
"self": "http://session/456"
}
}
Run Code Online (Sandbox Code Playgroud)
遗憾的是Go将匿名成员视为真正的命名事物,因此它采用了已定义的类型(Anything)并因此命名了JSON:
User JSON:
{
"Anything": {
"id": 123,
"name": "James Dean"
},
"_links": {
"self": "http://user/123"
}
}
Session JSON:
{
"Anything": {
"id": 456,
"userId": 123
},
"_links": {
"self": "http://session/456"
}
}
Run Code Online (Sandbox Code Playgroud)
匿名结构字段通常被编组,就好像它们的内部导出字段是外部结构中的字段一样,受到通常的Go可见性规则的限制,如下一段所述.在其JSON标记中给出名称的匿名结构字段被视为具有该名称,而不是匿名.
处理匿名结构字段是Go 1.1中的新功能.在Go 1.1之前,匿名结构字段被忽略.要强制忽略当前版本和早期版本中的匿名结构字段,请为该字段指定" - "的JSON标记.
这并没有说清楚是否有办法压扁,或暗示马歇尔勒我想做什么.
我确信,有一个特殊情况,可能有魔术名称,它具有重命名XML编组器中XML文档的根元素的特殊含义.
在这种情况下,我也没有以任何方式附加代码,我的用例是有一个接收interface{}, *http.Request, http.ResponseWriter和写回HATEOAS文档的函数,打开传递的类型,以推断要写回的链接进入JSON.(从而访问请求,请求主机,端口,方案等,以及类型本身以推断URL和已知字段等)
工作游乐场链接:http://play.golang.org/p/_r-bQIw347
其要点是这样的;通过使用 Reflect 包,我们循环遍历想要序列化的结构体字段,并将它们映射到 amap[string]interface{}我们现在可以保留原始结构体的平面结构,而无需引入新字段。
买者自负,可能应该针对此代码中的某些假设进行多次检查。例如,它假设MarshalHateoas总是接收指向值的指针。
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))
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6176 次 |
| 最近记录: |