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

9w11ddsr  于 2023-02-06  发布在  Go
关注(0)|答案(8)|浏览(479)

我正在使用带有JSON代理的谷歌grpc。由于某种原因,我需要从 *.pb.go文件中生成的结构中删除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"`
}

但是我需要从生成的结构体中删除omitempty标记,我该怎么做呢?

qc6wkl3g

qc6wkl3g1#

如果您使用的是grpc-gateway,并且需要在json封送处理期间提供缺省值,则可以考虑在创建servemux时添加以下选项

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

在grpc-gateway之外,如果要编组协议缓冲区消息,请使用google.golang.org/protobuf/encoding/protojson(*)包而不是encoding/json

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

(*)google.golang.org/protobuf取代了现在的deprecatedgithub.com/golang/protobuf及其jsonpb封装。

km0tfn4u

km0tfn4u2#

[更]便携的解决方案:
通过protoc生成后,使用sed剥离标签。
我在go中实际使用的例子:在生成 *.pb.go文件后生成脚本:

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

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

jw5wzhpr

jw5wzhpr3#

您可以尝试使用gogo proto(https://github.com/gogo/protobuf)和jsontag扩展,您的proto消息将如下所示

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

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

webghufk

webghufk4#

我发现omitempty json标记被硬编码到protoc-gen-go源代码的第1778行:

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

这将是很容易改变源代码,使一个新的protoc-gen-go二进制自己。
值得注意的是,这可能是不可取的,出于几个原因不推荐,特别是因为如果需要重新生成protobufs,您将负责确保被破解的二进制文件 * 总是 * 得到使用。

nzk0hqpo

nzk0hqpo5#

我发布了一个更新的Deesilence的答案,与最新的protobuf版本(在写作的时候)。

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

m := protojson.MarshalOptions{EmitUnpopulated: true}
resp, err := m.Marshal(w)
rqmkfv5c

rqmkfv5c6#

jsonpb包下的封送拆收器有一个EmitDefaults字段。将其设置为true,将忽略struct中的omitempty标记。
https://godoc.org/github.com/golang/protobuf/jsonpb#JSONPBMarshaler

af7jpaap

af7jpaap7#

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

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

其中args:

  1. -i ""表示保持文件的相同名称
  2. -e "s/,omitempty//g" =要替换的格式,如"s/SEARCH/INSERT/g"
qco9c6ql

qco9c6ql8#

可以将encoding/json包复制到自己的文件夹中,例如my_json,并将omitEmpty字段修改为false,使用my_json.Marshal()将struct编码为json string。

相关问题