I guess json.Marshal(protoResps)
does not work for you because the document for protojson
states:
This package produces a different output than the standard "encoding/json" package, which does not operate correctly on protocol buffer messages.
One workaround is still to utilize the encoding/json
, but marshal/unmarshal each item with the protojson
pakcage.
Option 1: Implement json.Marshaler
and json.Unmarshaler
If ProtoResp
is a local type, modify it to implement the Marshaler
and Unmarshaler
interfaces:
import (
"google.golang.org/protobuf/encoding/protojson"
)
func (r *ProtoResp) MarshalJSON() ([]byte, error) {
return protojson.Marshal(r)
}
func (r *ProtoResp) UnmarshalJSON(data []byte) error {
return protojson.Unmarshal(data, r)
}
Then it's safe to use the encoding/json
package to marshal/unmarshal []*ProtoResp
(an instance of ProtoResp
should not be copied, most of the time, you want to hold a pointer instead. I will use *ProtoResp
from now on).
Option 2: Use json.RawMessage
to delay the encoding/decoding
If ProtoResp
is not a local type, a workaround is to use json.RawMessage
to delay the encoding/decoding. This approach consumes more memory.
import (
"encoding/json"
"google.golang.org/protobuf/encoding/protojson"
)
func Marshal(protoResps []*ProtoResp) ([]byte, error) {
raw := make([]json.RawMessage, len(protoResps))
for i, p := range protoResps {
r, err := protojson.Marshal(p)
if err != nil {
return nil, err
}
raw[i] = r
}
return json.Marshal(raw)
}
func Unmarshal(data []byte) ([]*ProtoResp, error) {
var raw []json.RawMessage
if err := json.Unmarshal(data, &raw); err != nil {
return nil, err
}
protoResps := make([]*ProtoResp, len(raw))
for i, r := range raw {
p := &ProtoResp{}
if err := protojson.Unmarshal(r, p); err != nil {
return nil, err
}
protoResps[i] = p
}
return protoResps, nil
}