golang protobuf从生成的json标记中删除空标记

golang protobuf从生成的json标记中删除空标记,go,grpc,protocol-buffers,proto3,Go,Grpc,Protocol Buffers,Proto3,我正在使用带有json代理的google grpc。出于某种原因,我需要从*.pb.go文件中生成的结构中删除ommitempty标记 如果我有这样的原始信息 message Status { int32 code = 1; string message = 2; } type Status struct { Code int32 `protobuf:"varint,1,opt,name=code" json:"code,omitempty"` Message string `

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

如果我有这样的原始信息

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"`
}
生成的结构如下所示

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

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

我发现
省略empty
json标记已硬编码到protoc gen的第1778行:

tag := fmt.Sprintf("protobuf:%s json:%q",
    g.goTag(message, field, wiretype), jsonName+",omitempty")
这将很容易改变源代码,并使一个新的protoc gen变为二进制


值得注意的是,这可能是不可取的,不建议这样做有几个原因,特别是因为如果需要重新生成protobufs,您将负责确保始终使用被黑客攻击的二进制文件。

一个[更]可移植的解决方案:

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

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

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


注意:
sed-i
(内联替换)在这里不使用,因为该标志在标准OS-X和Linux之间不可移植。

您可以将编码/json包复制到自己的文件夹中,例如my_json,并将字段修改为false,然后使用
my_json.Marshal()< /COD>将Stutt编码为JSON String。

< P>如果您使用GRPC网关,并且需要在JSON封送过程中存在默认值,则可以在创建ServMUX

时考虑添加以下选项
    gwmux := runtime.NewServeMux(runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{OrigName: true, EmitDefaults: true}))
在grpc网关之外,如果要封送协议缓冲区消息,请使用
github.com/golang/protobuf/jsonpb
包,而不是
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
}

您可以尝试使用gogo proto() 使用jsontag扩展,您的proto消息如下所示

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

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

jsonpb包下的封送拆收器有一个EmitDefaults字段。将此设置为true,将忽略struct中的ommitempty标记

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

sed -i "" -e "s/,omitempty//g" ./api/proto/*.go
其中args:

  • -i”“
    的意思是保持文件名相同
  • -e“s/,省略空的//g”
    =要替换的格式,如
    “s/SEARCH/INSERT/g”

  • 你需要原型buf工作正常吗?proto-buf需要这些标签。问题是@jiangid,我正在用我的一个int-feld发送一个0值。但当我发送0值时,grpc网关会忽略该值。我知道还有其他方法,但我想知道如何删除省略空标记。@Sadlil我不确定我是否理解您的问题。如果您发送一个
    0
    值,它将被忽略,因此该字段将保持不变-如果您使用的是零值结构(无论如何,您应该这样做)。我的问题是当我将该结构解析为json时,代码的值为0。json中会忽略该值。但是我需要这个值存在。@Sadlil如果你明确声明:
    struct.Field=proto.Uint64(0)
    它不应该是空的。3年多前的这个答案已经建议使用
    sed
    作为后处理:你没有为源代码添加永久链接,现在很好!此外,
    gogo
    支持自定义标记,例如
    [(gogoproto.moretags)=“数据存储:\”-\”]
    。要切换到
    gogo
    ,只需将
    protoc--go\u out=
    更改为
    protoc--gogofast\u out=
    (注意:gogofast也比googleproto快5..10倍!)