Skip to content

Commit 29f43b7

Browse files
committed
protojson: add UseHexForBytes option
1 parent c33baa8 commit 29f43b7

File tree

2 files changed

+38
-3
lines changed

2 files changed

+38
-3
lines changed

encoding/protojson/decode.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package protojson
66

77
import (
88
"encoding/base64"
9+
"encoding/hex"
910
"fmt"
1011
"math"
1112
"strconv"
@@ -41,6 +42,10 @@ type UnmarshalOptions struct {
4142
// If DiscardUnknown is set, unknown fields and enum name values are ignored.
4243
DiscardUnknown bool
4344

45+
// If UseHexForBytes is set, bytes fields are un-marshaled as hex
46+
// strings instead of base64.
47+
UseHexForBytes bool
48+
4449
// Resolver is used for looking up types when unmarshaling
4550
// google.protobuf.Any messages or extension fields.
4651
// If nil, this defaults to using protoregistry.GlobalTypes.
@@ -338,8 +343,14 @@ func (d decoder) unmarshalScalar(fd protoreflect.FieldDescriptor) (protoreflect.
338343
}
339344

340345
case protoreflect.BytesKind:
341-
if v, ok := unmarshalBytes(tok); ok {
342-
return v, nil
346+
if d.opts.UseHexForBytes {
347+
if v, ok := unmarshalBytesFromHex(tok); ok {
348+
return v, nil
349+
}
350+
} else {
351+
if v, ok := unmarshalBytes(tok); ok {
352+
return v, nil
353+
}
343354
}
344355

345356
case protoreflect.EnumKind:
@@ -488,6 +499,19 @@ func unmarshalBytes(tok json.Token) (protoreflect.Value, bool) {
488499
return protoreflect.ValueOfBytes(b), true
489500
}
490501

502+
func unmarshalBytesFromHex(tok json.Token) (protoreflect.Value, bool) {
503+
if tok.Kind() != json.String {
504+
return protoreflect.Value{}, false
505+
}
506+
507+
s := tok.ParsedString()
508+
b, err := hex.DecodeString(s)
509+
if err != nil {
510+
return protoreflect.Value{}, false
511+
}
512+
return protoreflect.ValueOfBytes(b), true
513+
}
514+
491515
func unmarshalEnum(tok json.Token, fd protoreflect.FieldDescriptor, discardUnknown bool) (protoreflect.Value, bool) {
492516
switch tok.Kind() {
493517
case json.String:

encoding/protojson/encode.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package protojson
66

77
import (
88
"encoding/base64"
9+
"encoding/hex"
910
"fmt"
1011

1112
"google.golang.org/protobuf/internal/encoding/json"
@@ -102,6 +103,10 @@ type MarshalOptions struct {
102103
// a strict superset of the latter.
103104
EmitDefaultValues bool
104105

106+
// If UseHexForBytes is set, bytes fields are marshaled as hex strings
107+
// instead of base64.
108+
UseHexForBytes bool
109+
105110
// Resolver is used for looking up types when expanding google.protobuf.Any
106111
// messages. If nil, this defaults to using protoregistry.GlobalTypes.
107112
Resolver interface {
@@ -324,7 +329,13 @@ func (e encoder) marshalSingular(val protoreflect.Value, fd protoreflect.FieldDe
324329
e.WriteFloat(val.Float(), 64)
325330

326331
case protoreflect.BytesKind:
327-
e.WriteString(base64.StdEncoding.EncodeToString(val.Bytes()))
332+
var encoded string
333+
if e.opts.UseHexForBytes {
334+
encoded = hex.EncodeToString(val.Bytes())
335+
} else {
336+
encoded = base64.StdEncoding.EncodeToString(val.Bytes())
337+
}
338+
e.WriteString(encoded)
328339

329340
case protoreflect.EnumKind:
330341
if fd.Enum().FullName() == genid.NullValue_enum_fullname {

0 commit comments

Comments
 (0)