内容简介:在日常中json数据格式应用场景很多。比如在restful请求/返回、业务通信协议、消息(nsq/kafka),广泛使用json。但是目前存在如下问题考虑到golang里可以直接根据struct序列化成json,我们很自然的想到的是通过生成struct结构来实现。想想常用的描述协议的2个格式(protobuf、thrift),也可以用来生成struct结构。这里考虑到thrift改动太大,用protobuf描述更好些。一个描述示例如下:
背景
json格式不便描述/统一管理
在日常中json数据格式应用场景很多。比如在restful请求/返回、业务通信协议、消息(nsq/kafka),广泛使用json。但是目前存在如下问题
- json数据协议分散在代码里,没有一个统一的描述方式
- json使用往往使用map结构,然后序列化。造成上下游使用混乱,容易出错
-
如果使用struct方式定义,那么需要手动写代码,很是繁琐
比如以下示例:
json格式如下:
{
"id": 123,
"name": "fangming",
"age": 18,
"occ": {"id": 111, "industry": "professor"},
"occs": [
{"id": 111, "industry": "professor"},
{"id": 222, "industry": "engineer"}
],
}
为了描述他我们不得不定义一个结构,然后序列化
type User struct {
Id int64 `json:"id"`
Name string `json:"name"`
Age int32 `json:"age"`
Occ *Occupation `json:"occ"`
Occs []*Occupation `json:"occs"`
}
type Occupation struct {
Id int64 `json:"id"`
Industry string `json:"industry"`
}
方案
用protobuf协议描述json
考虑到golang里可以直接根据struct序列化成json,我们很自然的想到的是通过生成struct结构来实现。想想常用的描述协议的2个格式(protobuf、thrift),也可以用来生成struct结构。这里考虑到thrift改动太大,用protobuf描述更好些。
一个描述示例如下:
message User {
required int64 id = 1;
required string name = 2;
required int32 age = 3;
optional Occupation occ = 4;
repeated Occupation occs = 5;
}
message Occupation {
required int64 id = 1;
required string industry = 2;
}
// 代表的json结构如下
{
"id": 123,
"name": "fangming",
"age": 18,
"occ": {"id": 111, "industry": "professor"},
"occs": [
{"id": 111, "industry": "professor"},
{"id": 222, "industry": "engineer"}
],
}
实现方案
直接基于protoc支持的扩展功能,写扩展插件即可。这里开发自己的插件:gogofmqjson
实现细节
后续有时间再更新
git地址
https:// github.com/buptbill220/ protobuf/tree/master
支持特性
- json编码完整支持required、optional字段语义检测;required字段不填序列化/反序列化报错
- 比用protobuf本身生成更简洁的代码
- 生成支持json的marshal & unmarshal方法
- 支持Set方法(主要是解决成员变量为指针类型,需要手动使用&)
- Set方法支持builder模式
protobuf其他特性
- 支持Set方法(主要是解决成员变量为指针类型,需要手动使用&)
- Set方法支持builder模式
安装使用
json协议代码生成
- go get http:// github.com/buptbill220/ protobuf/protoc-gen-gogofmqjson
- protoc --gogofmqjson_out=./ xxx.proto
无缝迁移gogo
- go get http:// github.com/buptbill220/ protobuf/protoc-gen-gogo
- go get http:// github.com/buptbill220/ protobuf/protoc-gen-gogofast
- go get http:// github.com/buptbill220/ protobuf/protoc-gen-gofast
生成代码示例
// FmqJsonCode generated by protoc-gen-gogofmqjson. Do NOT EDIT
// Author: fangming
// Email: fangming@bytedance.com
// source: test.proto
// It is generated from these files:
// test.proto
// It has these top-level messages:
//== User
//== Occupation
package test
import (
encoding_json "encoding/json"
fmt "fmt"
)
type User struct {
Id *int64 `json:"id"`
Name *string `json:"name"`
Age *int32 `json:"age"`
Occ *Occupation `json:"occ"`
Occs []*Occupation `json:"occs"`
}
func (m *User) Reset() { *m = User{} }
func (*User) ProtoMessage() {}
func (m *User) GetId() int64 {
if m != nil && m.Id != nil {
return *m.Id
}
return 0
}
func (m *User) SetId(v int64) *User {
if m != nil {
m.Id = &v
}
return m
}
func (m *User) GetName() string {
if m != nil && m.Name != nil {
return *m.Name
}
return ""
}
func (m *User) SetName(v string) *User {
if m != nil {
m.Name = &v
}
return m
}
func (m *User) GetAge() int32 {
if m != nil && m.Age != nil {
return *m.Age
}
return 0
}
func (m *User) SetAge(v int32) *User {
if m != nil {
m.Age = &v
}
return m
}
func (m *User) GetOcc() *Occupation {
if m != nil {
return m.Occ
}
return nil
}
func (m *User) SetOcc(v *Occupation) *User {
if m != nil {
m.Occ = v
}
return m
}
func (m *User) GetOccs() []*Occupation {
if m != nil {
return m.Occs
}
return nil
}
func (m *User) SetOccs(v []*Occupation) *User {
if m != nil {
m.Occs = v
}
return m
}
type Occupation struct {
Id *int64 `json:"id"`
Industry *string `json:"industry"`
}
func (m *Occupation) Reset() { *m = Occupation{} }
func (*Occupation) ProtoMessage() {}
func (m *Occupation) GetId() int64 {
if m != nil && m.Id != nil {
return *m.Id
}
return 0
}
func (m *Occupation) SetId(v int64) *Occupation {
if m != nil {
m.Id = &v
}
return m
}
func (m *Occupation) GetIndustry() string {
if m != nil && m.Industry != nil {
return *m.Industry
}
return ""
}
func (m *Occupation) SetIndustry(v string) *Occupation {
if m != nil {
m.Industry = &v
}
return m
}
func (m *User) Marshal() ([]byte, error) {
if m == nil {
return nil, fmt.Errorf("msg User is nil")
}
if err := m.Validate(); err != nil {
return nil, err
}
return encoding_json.Marshal(m)
}
func (m *User) Unmarshal(data []byte) error {
if m == nil {
return fmt.Errorf("msg User is nil")
}
if err := encoding_json.Unmarshal(data, m); err != nil {
return err
}
if err := m.Validate(); err != nil {
return err
}
return nil
}
func (m *Occupation) Marshal() ([]byte, error) {
if m == nil {
return nil, fmt.Errorf("msg Occupation is nil")
}
if err := m.Validate(); err != nil {
return nil, err
}
return encoding_json.Marshal(m)
}
func (m *Occupation) Unmarshal(data []byte) error {
if m == nil {
return fmt.Errorf("msg Occupation is nil")
}
if err := encoding_json.Unmarshal(data, m); err != nil {
return err
}
if err := m.Validate(); err != nil {
return err
}
return nil
}
func (m *User) Validate() error {
if m == nil {
return fmt.Errorf("msg User is nil")
}
if m.Id == nil {
return fmt.Errorf("required field User.Id is nil")
}
if m.Name == nil {
return fmt.Errorf("required field User.Name is nil")
}
if m.Age == nil {
return fmt.Errorf("required field User.Age is nil")
}
if m.Occ != nil {
if err := m.Occ.Validate(); err != nil {
return err
}
}
for _, p := range m.Occs {
if err := p.Validate(); err != nil {
return err
}
}
return nil
}
func (m *Occupation) Validate() error {
if m == nil {
return fmt.Errorf("msg Occupation is nil")
}
if m.Id == nil {
return fmt.Errorf("required field Occupation.Id is nil")
}
if m.Industry == nil {
return fmt.Errorf("required field Occupation.Industry is nil")
}
return nil
}
测试使用/示例
func testUser() {
user := &User{}
data, err := user.Marshal()
if err != nil {
fmt.Printf("1: user marshal err %s\n", err.Error())
}
fmt.Printf("1: user marshal data %s\n", string(data))
data, err = user.SetId(1).Marshal()
if err != nil {
fmt.Printf("2: user marshal err %s\n", err.Error())
}
fmt.Printf("2: user marshal data %s\n", string(data))
data, err = user.SetAge(28).Marshal()
if err != nil {
fmt.Printf("3: user marshal err %s\n", err.Error())
}
fmt.Printf("3: user marshal data %s\n", string(data))
data, err = user.SetName("fangming").Marshal()
if err != nil {
fmt.Printf("4: user marshal err %s\n", err.Error())
}
fmt.Printf("4: user marshal data %s\n", string(data))
occ := &Occupation{}
occ.SetId(1)
data, err = user.SetOcc(occ).Marshal()
if err != nil {
fmt.Printf("5: user marshal err %s\n", err.Error())
}
fmt.Printf("5: user marshal data %s\n", string(data))
occ.SetIndustry("computer")
data, err = user.SetOcc(occ).Marshal()
if err != nil {
fmt.Printf("6: user marshal err %s\n", err.Error())
}
fmt.Printf("6: user marshal data %s\n", string(data))
occs := []*Occupation{}
occ = &Occupation{}
occ.SetId(2)
occs = append(occs, occ)
data, err = user.SetOccs(occs).Marshal()
if err != nil {
fmt.Printf("7: user marshal err %s\n", err.Error())
}
fmt.Printf("7: user marshal data %s\n", string(data))
occ.SetIndustry("teacher")
occs = append(occs, occ)
data, err = user.SetOccs(occs).Marshal()
if err != nil {
fmt.Printf("8: user marshal err %s\n", err.Error())
}
fmt.Printf("8: user marshal data %s\n", string(data))
}
/* 输出如下
1: user marshal err required field User.Id is nil
1: user marshal data
2: user marshal err required field User.Name is nil
2: user marshal data
3: user marshal err required field User.Name is nil
3: user marshal data
4: user marshal data {"id":1,"name":"fangming","age":28,"occ":null,"occs":null}
5: user marshal err required field Occupation.Industry is nil
5: user marshal data
6: user marshal data {"id":1,"name":"fangming","age":28,"occ":{"id":1,"industry":"computer"},"occs":null}
7: user marshal err required field Occupation.Industry is nil
7: user marshal data
8: user marshal data {"id":1,"name":"fangming","age":28,"occ":{"id":1,"industry":"computer"},"occs":[{"id":2,"industry":"teacher"},{"id":2,"industry":"teacher"}]}
*/
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- changelog 日志自动生成插件
- 如何实现一行命令自动生成 Flutter 插件
- 使用Gradle插件生成资源ID映射文件
- IDEA 插件: EasyCode一键生成所需代码~
- web-flash发布了代码生成插件
- 推荐一款快速生成海报的微信小插件
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Rationality for Mortals
Gerd Gigerenzer / Oxford University Press, USA / 2008-05-02 / USD 65.00
Gerd Gigerenzer's influential work examines the rationality of individuals not from the perspective of logic or probability, but from the point of view of adaptation to the real world of human behavio......一起来看看 《Rationality for Mortals》 这本书的介绍吧!