32

我正在使用带有 json 代理的 google grpc。出于某种原因,我需要omitempty从 *.pb.go 文件中生成的结构中删除标签。

如果我有这样的原始消息

message Status {
  int32 code = 1;
  string message = 2;
}

生成的结构看起来像这样

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"`
}

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

4

8 回答 8

19

如果您正在使用 grpc-gateway 并且您需要在 json 封送期间存在默认值,您可以考虑在创建 servermux 时添加以下选项

    gwmux := runtime.NewServeMux(runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{OrigName: true, EmitDefaults: true}))

在 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
}
于 2018-04-26T13:59:12.470 回答
12

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

通过sed生成后用于剥离标签protoc

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

ls *.pb.go | xargs -n1 -IX bash -c 'sed s/,omitempty// X > X.tmp && mv X{.tmp,}'

注意:sed -i(inline-replacement) 在这里没有使用,因为该标志不能在标准 OS-X 和 Linux 之间移植。

于 2016-05-19T23:05:45.970 回答
9

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

message Status {
  int32 code = 1 [(gogoproto.jsontag) = "code"];
  string message = 2 [(gogoproto.jsontag) = "message"];
}

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

于 2018-10-08T18:25:41.023 回答
7

我发现json 标记在 1778 行附近omitempty被硬编码到 protoc-gen-go源代码中:

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

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

值得注意的是,出于多种原因,这可能是不可取的并且不推荐,特别是因为您将负责确保在需要重新生成 protobuf时始终使用被破解的二进制文件。

于 2016-01-12T01:42:01.097 回答
2

jsonpb 包下的 Marshaler 有一个 EmitDefaults 字段。将此设置为 true,将忽略 struct 中的 omitempty 标记。

https://godoc.org/github.com/golang/protobuf/jsonpb#JSONPBMarshaler

于 2019-04-01T20:17:10.147 回答
1

您可以使用“sed”命令从文件中删除此文本,如下所示

sed -i "" -e "s/,omitempty//g" ./api/proto/*.go

其中参数:

  1. -i ""意思是保持相同的文件名
  2. -e "s/,omitempty//g"=要替换的格式"s/SEARCH/INSERT/g"
于 2019-10-27T13:43:11.000 回答
0

您可以将 encoding/json 包复制到您自己的文件夹,例如 my_json,并将omitEmpty字段修改为 false,并用于my_json.Marshal()将结构编码为 json 字符串。

于 2018-02-09T11:56:17.563 回答
0

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

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

m := protojson.MarshalOptions{EmitUnpopulated: true}
resp, err := m.Marshal(w)
于 2022-02-19T03:24:23.960 回答