Skip to content

Commit

Permalink
protojson: add UseHexForBytes option
Browse files Browse the repository at this point in the history
  • Loading branch information
bhandras committed Sep 26, 2024
1 parent c33baa8 commit fb21b69
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 3 deletions.
28 changes: 26 additions & 2 deletions encoding/protojson/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package protojson

import (
"encoding/base64"
"encoding/hex"
"fmt"
"math"
"strconv"
Expand Down Expand Up @@ -41,6 +42,10 @@ type UnmarshalOptions struct {
// If DiscardUnknown is set, unknown fields and enum name values are ignored.
DiscardUnknown bool

// If UseHexForBytes is set, bytes fields are un-marshaled as hex
// strings instead of base64.
UseHexForBytes bool

// Resolver is used for looking up types when unmarshaling
// google.protobuf.Any messages or extension fields.
// If nil, this defaults to using protoregistry.GlobalTypes.
Expand Down Expand Up @@ -338,8 +343,14 @@ func (d decoder) unmarshalScalar(fd protoreflect.FieldDescriptor) (protoreflect.
}

case protoreflect.BytesKind:
if v, ok := unmarshalBytes(tok); ok {
return v, nil
if d.opts.UseHexForBytes {
if v, ok := unmarshalBytesFromHex(tok); ok {
return v, nil
}
} else {
if v, ok := unmarshalBytes(tok); ok {
return v, nil
}
}

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

func unmarshalBytesFromHex(tok json.Token) (protoreflect.Value, bool) {
if tok.Kind() != json.String {
return protoreflect.Value{}, false
}

s := tok.ParsedString()
b, err := hex.DecodeString(s)
if err != nil {
return protoreflect.Value{}, false
}
return protoreflect.ValueOfBytes(b), true
}

func unmarshalEnum(tok json.Token, fd protoreflect.FieldDescriptor, discardUnknown bool) (protoreflect.Value, bool) {
switch tok.Kind() {
case json.String:
Expand Down
13 changes: 12 additions & 1 deletion encoding/protojson/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package protojson

import (
"encoding/base64"
"encoding/hex"
"fmt"

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

// If UseHexForBytes is set, bytes fields are marshaled as hex strings
// instead of base64.
UseHexForBytes bool

// Resolver is used for looking up types when expanding google.protobuf.Any
// messages. If nil, this defaults to using protoregistry.GlobalTypes.
Resolver interface {
Expand Down Expand Up @@ -324,7 +329,13 @@ func (e encoder) marshalSingular(val protoreflect.Value, fd protoreflect.FieldDe
e.WriteFloat(val.Float(), 64)

case protoreflect.BytesKind:
e.WriteString(base64.StdEncoding.EncodeToString(val.Bytes()))
var encoded string
if e.opts.UseHexForBytes {
encoded = hex.EncodeToString(val.Bytes())
} else {
encoded = base64.StdEncoding.EncodeToString(val.Bytes())
}
e.WriteString(encoded)

case protoreflect.EnumKind:
if fd.Enum().FullName() == genid.NullValue_enum_fullname {
Expand Down

0 comments on commit fb21b69

Please sign in to comment.