golang protobuf从生成的json标签中删除omitempty标签

sad*_*lil 14 go protocol-buffers grpc proto3

我正在使用谷歌grpc与json代理.由于某种原因,我需要omitempty从*.pb.go文件中生成的结构中删除标记.

如果我有这样的原型消息

message Status {
  int32 code = 1;
  string message = 2;
}
Run Code Online (Sandbox Code Playgroud)

生成的结构看起来像这样

type Status struct {
  Code int32 `protobuf:"varint,1,opt,name=code" json:"code,omitempty"`
  Message string `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"`
}
Run Code Online (Sandbox Code Playgroud)

但我需要omitempty从生成的结构中删除标记.我怎样才能做到这一点?

小智 18

如果您使用的是 grpc-gateway 并且需要在 json 编组期间提供默认值,您可以考虑在创建 servemux 时添加以下选项

    gwmux := runtime.NewServeMux(runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{OrigName: true, EmitDefaults: true}))
Run Code Online (Sandbox Code Playgroud)

在 grpc-gateway 之外,如果要编组 protocul 缓冲区消息,请使用github.com/golang/protobuf/jsonpbpackage 而不是encoding/json

func sendProtoMessage(resp proto.Message, w http.ResponseWriter) {
    w.Header().Set("Content-Type", "application/json; charset=utf-8")
    m := jsonpb.Marshaler{EmitDefaults: true}
    m.Marshal(w, resp) // You should check for errors here
}
Run Code Online (Sandbox Code Playgroud)


小智 9

您可以尝试使用 gogo proto ( https://github.com/gogo/protobuf ) 使用 jsontag 扩展名,您的 proto 消息看起来像

message Status {
  int32 code = 1 [(gogoproto.jsontag) = "code"];
  string message = 2 [(gogoproto.jsontag) = "message"];
}
Run Code Online (Sandbox Code Playgroud)

如果愿意,您还可以添加更多标签。


Jia*_* YD 7

我发现omitemptyjson 标签在 1778 行左右被硬编码到 protoc-gen-go源代码中

tag := fmt.Sprintf("protobuf:%s json:%q",
    g.goTag(message, field, wiretype), jsonName+",omitempty")
Run Code Online (Sandbox Code Playgroud)

更改源代码并自己制作新的 protoc-gen-go 二进制文件会很容易。

值得注意的是,这可能是不可取的并且不推荐,原因有几个,特别是因为如果需要重新生成 protobufs ,您将负责确保始终使用破解的二进制文件。


Jay*_*lor 7

[更多]便携式解决方案:

用于sed在生成via之后剥离标签protoc

在生成* .pb.go文件之后,我在go:generate脚本中实际使用的示例:

ls *.pb.go | xargs -n1 -IX bash -c 'sed s/,omitempty// X > X.tmp && mv X{.tmp,}'
Run Code Online (Sandbox Code Playgroud)

注意:sed -i此处未使用(inline-replacement),因为该标志在标准OS-X和Linux之间不可移植。


Pav*_*sev 5

我正在发布 DeeSilence 答案的更新,该答案适用于最新的 protobuf 版本(在撰写本文时)。

import "google.golang.org/protobuf/encoding/protojson"

m := protojson.MarshalOptions{EmitUnpopulated: true}
resp, err := m.Marshal(w)
Run Code Online (Sandbox Code Playgroud)