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.