'Converting Protobuf3 with enum to JSON in Go
How can I convert grpc/protobuf3 message to JSON where the enum is represented as string?
For example, the protobuf message:
enum Level {
    WARNING = 0;
    FATAL = 1;
    SEVERE = 2;
    ...
}
message Http {
    string message = 1;
    Level level = 2;
}
Is converted by:
j, _ := json.MarshalIndent(protoMessage, "", "\t")
To:
{
    "message": "Hello world!",
    "level": 2,
}
I wish to get:
{
    "message": "Hello world!",
    "level": "SEVERE",
}
Thanks
Solution 1:[1]
I found out that I should use the protobuf/jsonpb package and not the standard json package.
so:
j, _ := json.MarshalIndent(protoMessage, "", "\t")
Should be:
m := jsonpb.Marshaler{}
result, _ := m.MarshalToString(protoMessage)
Update
As noted bellow, jsonpb is depricated and the new solution is to use protojson
Solution 2:[2]
I found some of these modules (jsonpb) to be deprecated. What worked for me was the google encoding version:
import "google.golang.org/protobuf/encoding/protojson"
jsonString := protojson.Format(protoMessage)
Solution 3:[3]
Level is not a string though, it is an emum. There are really only two choices I see.
- Write a custom marshaller that does this for you
- Generate code that does this for you.
For #2, gogoprotobuf has an extension (still marked as experimental) that let's you do exactly this:
https://godoc.org/github.com/gogo/protobuf/plugin/enumstringer and https://github.com/gogo/protobuf/blob/master/extensions.md
Solution 4:[4]
For my use case, I wanted to write it to a file. Using the most recent packages as of this date, this was as close to a regular encoding/json marshal as I could get.
I used the google.golang.org/protobuf/encoding/protojson package and the .ProtoReflect().Interface() methods of my protocol buffer data structure.
package main
import (
    "io/ioutil"
    "log"
    "google.golang.org/protobuf/encoding/protojson"
    "myproject/proto"
)
func main() {
    myProtoStruct := proto.MyType{}
    data, err := protojson.Marshal(myProtoStruct.ProtoReflect().Interface())
    if err != nil {
        log.Fatalf("Failed to JSON marhsal protobuf.\nError: %s", err.Error())
    }
    err = ioutil.WriteFile("my.proto.dat", data, 0600)
    if err != nil {
        log.Fatalf("Failed to write protobuf data to file.\nError: %s", err.Error())
    }
    log.Println("Written to file.")
}
Solution 5:[5]
When it comes to serialize the json object, this would be helpful.
var msg bytes.Buffer
m := jsonpb.Marshaler{}
err := m.Marshal(&msg, event)
msg.Bytes() converts msg to byte stream.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source | 
|---|---|
| Solution 1 | |
| Solution 2 | Evan Moran | 
| Solution 3 | sberry | 
| Solution 4 | |
| Solution 5 | wthrain | 
