diff --git a/jsonpb/jsonpb.go b/jsonpb/jsonpb.go index 71985e64ff..0ad60eb618 100644 --- a/jsonpb/jsonpb.go +++ b/jsonpb/jsonpb.go @@ -53,10 +53,6 @@ import ( "github.com/golang/protobuf/proto" ) -var ( - byteArrayType = reflect.TypeOf([]byte{}) -) - // Marshaler is a configurable object for converting between // protocol buffer objects and a JSON representation for them. type Marshaler struct { @@ -374,7 +370,7 @@ func (m *Marshaler) marshalValue(out *errWriter, prop *proto.Properties, v refle v = reflect.Indirect(v) // Handle repeated elements. - if v.Type() != byteArrayType && v.Kind() == reflect.Slice { + if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 { out.write("[") comma := "" for i := 0; i < v.Len(); i++ { @@ -684,7 +680,7 @@ func unmarshalValue(target reflect.Value, inputValue json.RawMessage, prop *prot } // Handle arrays (which aren't encoded bytes) - if targetType != byteArrayType && targetType.Kind() == reflect.Slice { + if targetType.Kind() == reflect.Slice && targetType.Elem().Kind() != reflect.Uint8 { var slc []json.RawMessage if err := json.Unmarshal(inputValue, &slc); err != nil { return err diff --git a/jsonpb/jsonpb_test.go b/jsonpb/jsonpb_test.go index bed8b30b5f..c4cc3dd16a 100644 --- a/jsonpb/jsonpb_test.go +++ b/jsonpb/jsonpb_test.go @@ -282,6 +282,21 @@ func init() { } } +// Bytes is used to test that []byte type aliases are serialized to base64. +type Byte byte + +// Bytes is used to test that []byte type aliases are serialized to base64. +type Bytes []Byte + +// BytesMessage is used to test that []byte type aliases are serialized to base64. +type BytesMessage struct { + Bytes Bytes `protobuf:"bytes,1,opt,name=bytes,json=bytes" json:"bytes,omitempty"` +} + +func (*BytesMessage) Reset() {} +func (*BytesMessage) String() string { return "" } +func (*BytesMessage) ProtoMessage() {} + var marshalingTests = []struct { desc string marshaler Marshaler @@ -373,6 +388,7 @@ var marshalingTests = []struct { {"BoolValue", marshaler, &pb.KnownTypes{Bool: &wpb.BoolValue{Value: true}}, `{"bool":true}`}, {"StringValue", marshaler, &pb.KnownTypes{Str: &wpb.StringValue{Value: "plush"}}, `{"str":"plush"}`}, {"BytesValue", marshaler, &pb.KnownTypes{Bytes: &wpb.BytesValue{Value: []byte("wow")}}, `{"bytes":"d293"}`}, + {"BytesMessageValue", marshaler, &BytesMessage{Bytes: []Byte("wow")}, `{"bytes":"d293"}`}, } func TestMarshaling(t *testing.T) { @@ -445,6 +461,7 @@ var unmarshalingTests = []struct { {"BoolValue", `{"bool":true}`, &pb.KnownTypes{Bool: &wpb.BoolValue{Value: true}}}, {"StringValue", `{"str":"plush"}`, &pb.KnownTypes{Str: &wpb.StringValue{Value: "plush"}}}, {"BytesValue", `{"bytes":"d293"}`, &pb.KnownTypes{Bytes: &wpb.BytesValue{Value: []byte("wow")}}}, + {"BytesMessageValue", `{"bytes":"d293"}`, &BytesMessage{Bytes: []Byte("wow")}}, // `null` is also a permissible value. Let's just test one. {"null DoubleValue", `{"dbl":null}`, &pb.KnownTypes{Dbl: &wpb.DoubleValue{}}}, } diff --git a/proto/text.go b/proto/text.go index bd6f1ae5e4..8214ce326b 100644 --- a/proto/text.go +++ b/proto/text.go @@ -513,7 +513,7 @@ func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Propert switch v.Kind() { case reflect.Slice: // Should only be a []byte; repeated fields are handled in writeStruct. - if err := writeString(w, string(v.Interface().([]byte))); err != nil { + if err := writeString(w, string(v.Bytes())); err != nil { return err } case reflect.String: