Golang protobuf удалить тег omitempty из сгенерированных json-тегов
Я использую google grpc с помощью json-прокси. по какой-то причине мне нужно удалить теги 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
из сгенерированных структур. Как я могу это сделать?
Ответы
Ответ 1
A [более] портативное решение:
Используйте sed
для разделения тегов после генерации с помощью protoc
.
Пример того, что я действительно использую в своем ходу: сгенерируйте script после создания файлов *.pb.go:
ls *.pb.go | xargs -n1 -IX bash -c 'sed s/,omitempty// X > X.tmp && mv X{.tmp,}'
Примечание: sed -i
(inline-replacement) не используется здесь, потому что этот флаг не переносится между стандартными ОС-X и Linux.
Ответ 2
Если вы используете grpc-gateway и вам нужно, чтобы значения по умолчанию присутствовали во время маршалинга json, вы можете добавить следующую опцию при создании servemux
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
}
Ответ 3
Я обнаружил, что тег omitempty
json жестко закодирован в источник proto-gen-go вокруг строки 1778:
tag := fmt.Sprintf("protobuf:%s json:%q",
g.goTag(message, field, wiretype), jsonName+",omitempty")
будет легко сменить исходный код и создать новый проток-gen-go-бинар самостоятельно.
Стоит отметить, что это, вероятно, нецелесообразно и не рекомендуется по нескольким причинам, особенно потому, что тогда вы будете нести ответственность за то, чтобы бинарный файл с взломом всегда использовался, если протобуфы нуждаются в регенерации.
Ответ 4
Вы можете попробовать использовать gogo proto (https://github.com/gogo/protobuf). С расширением jsontag ваше сообщение proto будет выглядеть так:
message Status {
int32 code = 1 [(gogoproto.jsontag) = "code"];
string message = 2 [(gogoproto.jsontag) = "message"];
}
Вы также можете добавить больше тегов, если хотите.
Ответ 5
вы можете скопировать пакет encoding/json в свою собственную папку, например my_json, и изменить omitEmpty поле false и использовать my_json.Marshal()
для кодирования строки в строку json.
Ответ 6
Marshaler в пакете jsonpb имеет поле EmitDefaults. Установка этого значения в true будет просто игнорировать пропущенный тег в структуре.
https://godoc.org/github.com/golang/protobuf/jsonpb#JSONPBMarshaler