Skip to content

Commit 26f968c

Browse files
committed
jsonpb: Adds support for other []byte types to be base64 encoded.
The proto3 spec encodes the bytes type to be a base64 encoded string when marshalling to jsonpb. This adds support to jsonpb to correctly encode go types in the format `type Bytes []byte` into base64 instead of being represented as an uint8 array. While these types won't be generated by the standard protobuf compiler, they can be generated by others such as gogo protobuf.
1 parent cd85f19 commit 26f968c

File tree

3 files changed

+17
-7
lines changed

3 files changed

+17
-7
lines changed

jsonpb/jsonpb.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,6 @@ import (
5353
"github.com/golang/protobuf/proto"
5454
)
5555

56-
var (
57-
byteArrayType = reflect.TypeOf([]byte{})
58-
)
59-
6056
// Marshaler is a configurable object for converting between
6157
// protocol buffer objects and a JSON representation for them.
6258
type Marshaler struct {
@@ -372,7 +368,7 @@ func (m *Marshaler) marshalValue(out *errWriter, prop *proto.Properties, v refle
372368
v = reflect.Indirect(v)
373369

374370
// Handle repeated elements.
375-
if v.Type() != byteArrayType && v.Kind() == reflect.Slice {
371+
if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 {
376372
out.write("[")
377373
comma := ""
378374
for i := 0; i < v.Len(); i++ {
@@ -682,7 +678,7 @@ func unmarshalValue(target reflect.Value, inputValue json.RawMessage, prop *prot
682678
}
683679

684680
// Handle arrays (which aren't encoded bytes)
685-
if targetType != byteArrayType && targetType.Kind() == reflect.Slice {
681+
if targetType.Kind() == reflect.Slice && targetType.Elem().Kind() != reflect.Uint8 {
686682
var slc []json.RawMessage
687683
if err := json.Unmarshal(inputValue, &slc); err != nil {
688684
return err

jsonpb/jsonpb_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,18 @@ func init() {
282282
}
283283
}
284284

285+
// Bytes is used to test that []byte type aliases are serialized to base64.
286+
type Bytes []byte
287+
288+
// BytesMessage is used to test that []byte type aliases are serialized to base64.
289+
type BytesMessage struct {
290+
Bytes Bytes `protobuf:"bytes,1,opt,name=bytes,json=bytes" json:"bytes,omitempty"`
291+
}
292+
293+
func (*BytesMessage) Reset() {}
294+
func (*BytesMessage) String() string { return "" }
295+
func (*BytesMessage) ProtoMessage() {}
296+
285297
var marshalingTests = []struct {
286298
desc string
287299
marshaler Marshaler
@@ -373,6 +385,7 @@ var marshalingTests = []struct {
373385
{"BoolValue", marshaler, &pb.KnownTypes{Bool: &wpb.BoolValue{Value: true}}, `{"bool":true}`},
374386
{"StringValue", marshaler, &pb.KnownTypes{Str: &wpb.StringValue{Value: "plush"}}, `{"str":"plush"}`},
375387
{"BytesValue", marshaler, &pb.KnownTypes{Bytes: &wpb.BytesValue{Value: []byte("wow")}}, `{"bytes":"d293"}`},
388+
{"BytesMessageValue", marshaler, &BytesMessage{Bytes: []byte("wow")}, `{"bytes":"d293"}`},
376389
}
377390

378391
func TestMarshaling(t *testing.T) {
@@ -445,6 +458,7 @@ var unmarshalingTests = []struct {
445458
{"BoolValue", `{"bool":true}`, &pb.KnownTypes{Bool: &wpb.BoolValue{Value: true}}},
446459
{"StringValue", `{"str":"plush"}`, &pb.KnownTypes{Str: &wpb.StringValue{Value: "plush"}}},
447460
{"BytesValue", `{"bytes":"d293"}`, &pb.KnownTypes{Bytes: &wpb.BytesValue{Value: []byte("wow")}}},
461+
{"BytesMessageValue", `{"bytes":"d293"}`, &BytesMessage{Bytes: []byte("wow")}},
448462
// `null` is also a permissible value. Let's just test one.
449463
{"null DoubleValue", `{"dbl":null}`, &pb.KnownTypes{Dbl: &wpb.DoubleValue{}}},
450464
}

proto/text.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Propert
513513
switch v.Kind() {
514514
case reflect.Slice:
515515
// Should only be a []byte; repeated fields are handled in writeStruct.
516-
if err := writeString(w, string(v.Interface().([]byte))); err != nil {
516+
if err := writeString(w, string(v.Bytes())); err != nil {
517517
return err
518518
}
519519
case reflect.String:

0 commit comments

Comments
 (0)