Golang protobuf 从生成的 JSON 标签中移除 omitempty 标记。

huangapple go评论143阅读模式
英文:

golang protobuf remove omitempty tag from generated json tags

问题

我正在使用Google gRPC和JSON代理。由于某种原因,我需要从*.pb.go文件中生成的结构体中删除omitempty标签。

如果我有一个proto消息如下所示:

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标签。我该如何做到这一点?

英文:

I am using google grpc with a json proxy. for some reason i need to remove the omitempty tags from the struct generated in the *.pb.go files.

if i have a proto message like this

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

The generated struct looks like this

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

But My need is to remove the omitempty tag from the generated structs. How can i do this?

答案1

得分: 24

如果你正在使用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) // 在这里你应该检查错误
}

google.golang.org/protobuf取代了现在已被弃用的github.com/golang/protobuf及其jsonpb包。

英文:

If you are using grpc-gateway and you need the default values to be present during json marshaling, you may consider to add the following option when creating your servemux

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

Outside of grpc-gateway, if you want to marshal your protocol buffer message, use google.golang.org/protobuf/encoding/protojson (*) package instead of 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 replaces the now deprecated github.com/golang/protobuf and its jsonpb package.

答案2

得分: 16

一个更便携的解决方案:

在使用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之间不可移植。

英文:

A [more] portable solution:

Use sed to strip the tags after generating via protoc.

Example of what I actually use in my go:generate script after having generated the *.pb.go files:

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

Note: sed -i (inline-replacement) is not used here because that flag isn't portable between standard OS-X and Linux.

答案3

得分: 9

我发现omitempty json标签在protoc-gen-go的源代码中是硬编码的,大约在1778行附近:

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

你可以轻松地修改源代码并自己生成一个新的protoc-gen-go二进制文件。

值得注意的是,出于几个原因,这样做可能是不可取的,也不被推荐,特别是因为你将需要确保修改后的二进制文件始终被使用,如果需要重新生成protobufs。

英文:

I found that the omitempty json tag is hard-coded into the protoc-gen-go source around line 1778:

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

it will be easy changing the source and make a new protoc-gen-go binary yourself.

It's worth noting that this is likely inadvisable and not recommended for several reasons, particularly because you will then be responsible for ensuring that the hacked up binary always gets used if the protobufs need to be regenerated.

答案4

得分: 9

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

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

如果需要的话,你还可以添加更多的标签。

英文:

You can try using gogo proto (https://github.com/gogo/protobuf)
With the jsontag extension, your proto message would look like

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

You can also add more tags, if you like.

答案5

得分: 4

我正在发布一个更新,以适应最新的protobuf版本(在撰写本文时)。

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

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

I am posting an update to DeeSilence's answer that works with the latest protobuf version (at the moment of writing).

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

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

答案6

得分: 3

jsonpb包下的Marshaler结构体有一个EmitDefaults字段。将其设置为true,将会忽略结构体中的omitempty标签。

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

英文:

The Marshaler under the jsonpb package has a EmitDefaults field. Setting this to true, will just ignore the omitempty tag in struct.

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

答案7

得分: 2

你可以使用"sed"命令从文件中删除这段文本,如下所示:

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

其中参数解释如下:

  1. -i "" 表示保持文件名不变
  2. -e "s/,omitempty//g" 表示替换的格式,类似于 "s/搜索内容/替换内容/g" 的形式。
英文:

You could use "sed" command to remove this text from files like following

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

where args:

  1. -i "" is meaning that keep same name of files
  2. -e "s/,omitempty//g" = format to replace like "s/SEARCH/INSERT/g"

答案8

得分: 0

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

英文:

you can copy the encoding/json package to your own folder for example my_json, and modify omitEmpty field to false, and use my_json.Marshal() to encode the struct to json string.

答案9

得分: 0

要扩展@colm.anseo的编辑,指出google.golang.org/protobuf/encoding/protojson现在已被弃用,现在应该使用google.golang.org/protobuf。下面是一个示例,演示如何在不修改proto文件的情况下进行操作。

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

func main() {
	someProto := SomeProto{}
	marshaler := protojson.MarshalOptions{EmitUnpopulated: true}
	output, _ := marshaler.Marshal(someProto)
	...	
}

如果您不想修改生成的结构体/通过buf和bsr导入结构体,这是唯一的方法。

英文:

To expand on @colm.anseo's edit saying that the google.golang.org/protobuf/encoding/protojson is now deprecated and now google.golang.org/protobuf should be used, here is an example how to do it without modifying the proto.

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

func main() {
	someProto := SomeProto{}
	marshaler := protojson.MarshalOptions{EmitUnpopulated: true}
	output, _ := marshaler.Marshal(someProto)
	...	
}

This is the only way to do it if you don't want to modify the generated struct / are importing the struct via buf and the bsr.

huangapple
  • 本文由 发表于 2016年1月11日 15:32:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/34716238.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定