bunch of new files
This commit is contained in:
parent
907ebf48a7
commit
5116872acf
2
go.mod
2
go.mod
|
@ -177,3 +177,5 @@ require (
|
||||||
replace golang.org/x/time/rate => github.com/crowdsecurity/crowdsec/pkg/time/rate v0.0.0
|
replace golang.org/x/time/rate => github.com/crowdsecurity/crowdsec/pkg/time/rate v0.0.0
|
||||||
|
|
||||||
replace github.com/golang/protobuf => ./pkg/golang-protobuf
|
replace github.com/golang/protobuf => ./pkg/golang-protobuf
|
||||||
|
|
||||||
|
replace github.com/golang/protobuf/jsonpb => ./pkg/golang-protobuf/jsonpb
|
||||||
|
|
|
@ -11,3 +11,7 @@ require (
|
||||||
replace github.com/golang/protobuf => ../
|
replace github.com/golang/protobuf => ../
|
||||||
|
|
||||||
replace github.com/golang/protobuf/protoc-gen-go/descriptor => ../protoc-gen-go/descriptor
|
replace github.com/golang/protobuf/protoc-gen-go/descriptor => ../protoc-gen-go/descriptor
|
||||||
|
|
||||||
|
replace github.com/golang/protobuf/proto ../proto
|
||||||
|
|
||||||
|
replace github.com/golang/protobuf/jsonpb ../jsonpb
|
||||||
|
|
530
pkg/golang-protobuf/jsonpb/decode.go
Normal file
530
pkg/golang-protobuf/jsonpb/decode.go
Normal file
|
@ -0,0 +1,530 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package jsonpb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
|
protoV2 "google.golang.org/protobuf/proto"
|
||||||
|
"google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
"google.golang.org/protobuf/reflect/protoregistry"
|
||||||
|
)
|
||||||
|
|
||||||
|
const wrapJSONUnmarshalV2 = false
|
||||||
|
|
||||||
|
// UnmarshalNext unmarshals the next JSON object from d into m.
|
||||||
|
func UnmarshalNext(d *json.Decoder, m proto.Message) error {
|
||||||
|
return new(Unmarshaler).UnmarshalNext(d, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal unmarshals a JSON object from r into m.
|
||||||
|
func Unmarshal(r io.Reader, m proto.Message) error {
|
||||||
|
return new(Unmarshaler).Unmarshal(r, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalString unmarshals a JSON object from s into m.
|
||||||
|
func UnmarshalString(s string, m proto.Message) error {
|
||||||
|
return new(Unmarshaler).Unmarshal(strings.NewReader(s), m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshaler is a configurable object for converting from a JSON
|
||||||
|
// representation to a protocol buffer object.
|
||||||
|
type Unmarshaler struct {
|
||||||
|
// AllowUnknownFields specifies whether to allow messages to contain
|
||||||
|
// unknown JSON fields, as opposed to failing to unmarshal.
|
||||||
|
AllowUnknownFields bool
|
||||||
|
|
||||||
|
// AnyResolver is used to resolve the google.protobuf.Any well-known type.
|
||||||
|
// If unset, the global registry is used by default.
|
||||||
|
AnyResolver AnyResolver
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONPBUnmarshaler is implemented by protobuf messages that customize the way
|
||||||
|
// they are unmarshaled from JSON. Messages that implement this should also
|
||||||
|
// implement JSONPBMarshaler so that the custom format can be produced.
|
||||||
|
//
|
||||||
|
// The JSON unmarshaling must follow the JSON to proto specification:
|
||||||
|
// https://developers.google.com/protocol-buffers/docs/proto3#json
|
||||||
|
//
|
||||||
|
// Deprecated: Custom types should implement protobuf reflection instead.
|
||||||
|
type JSONPBUnmarshaler interface {
|
||||||
|
UnmarshalJSONPB(*Unmarshaler, []byte) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal unmarshals a JSON object from r into m.
|
||||||
|
func (u *Unmarshaler) Unmarshal(r io.Reader, m proto.Message) error {
|
||||||
|
return u.UnmarshalNext(json.NewDecoder(r), m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalNext unmarshals the next JSON object from d into m.
|
||||||
|
func (u *Unmarshaler) UnmarshalNext(d *json.Decoder, m proto.Message) error {
|
||||||
|
if m == nil {
|
||||||
|
return errors.New("invalid nil message")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the next JSON object from the stream.
|
||||||
|
raw := json.RawMessage{}
|
||||||
|
if err := d.Decode(&raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for custom unmarshalers first since they may not properly
|
||||||
|
// implement protobuf reflection that the logic below relies on.
|
||||||
|
if jsu, ok := m.(JSONPBUnmarshaler); ok {
|
||||||
|
return jsu.UnmarshalJSONPB(u, raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
mr := proto.MessageReflect(m)
|
||||||
|
|
||||||
|
// NOTE: For historical reasons, a top-level null is treated as a noop.
|
||||||
|
// This is incorrect, but kept for compatibility.
|
||||||
|
if string(raw) == "null" && mr.Descriptor().FullName() != "google.protobuf.Value" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if wrapJSONUnmarshalV2 {
|
||||||
|
// NOTE: If input message is non-empty, we need to preserve merge semantics
|
||||||
|
// of the old jsonpb implementation. These semantics are not supported by
|
||||||
|
// the protobuf JSON specification.
|
||||||
|
isEmpty := true
|
||||||
|
mr.Range(func(protoreflect.FieldDescriptor, protoreflect.Value) bool {
|
||||||
|
isEmpty = false // at least one iteration implies non-empty
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
if !isEmpty {
|
||||||
|
// Perform unmarshaling into a newly allocated, empty message.
|
||||||
|
mr = mr.New()
|
||||||
|
|
||||||
|
// Use a defer to copy all unmarshaled fields into the original message.
|
||||||
|
dst := proto.MessageReflect(m)
|
||||||
|
defer mr.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
|
||||||
|
dst.Set(fd, v)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal using the v2 JSON unmarshaler.
|
||||||
|
opts := protojson.UnmarshalOptions{
|
||||||
|
DiscardUnknown: u.AllowUnknownFields,
|
||||||
|
}
|
||||||
|
if u.AnyResolver != nil {
|
||||||
|
opts.Resolver = anyResolver{u.AnyResolver}
|
||||||
|
}
|
||||||
|
return opts.Unmarshal(raw, mr.Interface())
|
||||||
|
} else {
|
||||||
|
if err := u.unmarshalMessage(mr, raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return protoV2.CheckInitialized(mr.Interface())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unmarshaler) unmarshalMessage(m protoreflect.Message, in []byte) error {
|
||||||
|
md := m.Descriptor()
|
||||||
|
fds := md.Fields()
|
||||||
|
|
||||||
|
if jsu, ok := proto.MessageV1(m.Interface()).(JSONPBUnmarshaler); ok {
|
||||||
|
return jsu.UnmarshalJSONPB(u, in)
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(in) == "null" && md.FullName() != "google.protobuf.Value" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch wellKnownType(md.FullName()) {
|
||||||
|
case "Any":
|
||||||
|
var jsonObject map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(in, &jsonObject); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rawTypeURL, ok := jsonObject["@type"]
|
||||||
|
if !ok {
|
||||||
|
return errors.New("Any JSON doesn't have '@type'")
|
||||||
|
}
|
||||||
|
typeURL, err := unquoteString(string(rawTypeURL))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't unmarshal Any's '@type': %q", rawTypeURL)
|
||||||
|
}
|
||||||
|
m.Set(fds.ByNumber(1), protoreflect.ValueOfString(typeURL))
|
||||||
|
|
||||||
|
var m2 protoreflect.Message
|
||||||
|
if u.AnyResolver != nil {
|
||||||
|
mi, err := u.AnyResolver.Resolve(typeURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m2 = proto.MessageReflect(mi)
|
||||||
|
} else {
|
||||||
|
mt, err := protoregistry.GlobalTypes.FindMessageByURL(typeURL)
|
||||||
|
if err != nil {
|
||||||
|
if err == protoregistry.NotFound {
|
||||||
|
return fmt.Errorf("could not resolve Any message type: %v", typeURL)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m2 = mt.New()
|
||||||
|
}
|
||||||
|
|
||||||
|
if wellKnownType(m2.Descriptor().FullName()) != "" {
|
||||||
|
rawValue, ok := jsonObject["value"]
|
||||||
|
if !ok {
|
||||||
|
return errors.New("Any JSON doesn't have 'value'")
|
||||||
|
}
|
||||||
|
if err := u.unmarshalMessage(m2, rawValue); err != nil {
|
||||||
|
return fmt.Errorf("can't unmarshal Any nested proto %v: %v", typeURL, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
delete(jsonObject, "@type")
|
||||||
|
rawJSON, err := json.Marshal(jsonObject)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't generate JSON for Any's nested proto to be unmarshaled: %v", err)
|
||||||
|
}
|
||||||
|
if err = u.unmarshalMessage(m2, rawJSON); err != nil {
|
||||||
|
return fmt.Errorf("can't unmarshal Any nested proto %v: %v", typeURL, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rawWire, err := protoV2.Marshal(m2.Interface())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't marshal proto %v into Any.Value: %v", typeURL, err)
|
||||||
|
}
|
||||||
|
m.Set(fds.ByNumber(2), protoreflect.ValueOfBytes(rawWire))
|
||||||
|
return nil
|
||||||
|
case "BoolValue", "BytesValue", "StringValue",
|
||||||
|
"Int32Value", "UInt32Value", "FloatValue",
|
||||||
|
"Int64Value", "UInt64Value", "DoubleValue":
|
||||||
|
fd := fds.ByNumber(1)
|
||||||
|
v, err := u.unmarshalValue(m.NewField(fd), in, fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.Set(fd, v)
|
||||||
|
return nil
|
||||||
|
case "Duration":
|
||||||
|
v, err := unquoteString(string(in))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d, err := time.ParseDuration(v)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("bad Duration: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sec := d.Nanoseconds() / 1e9
|
||||||
|
nsec := d.Nanoseconds() % 1e9
|
||||||
|
m.Set(fds.ByNumber(1), protoreflect.ValueOfInt64(int64(sec)))
|
||||||
|
m.Set(fds.ByNumber(2), protoreflect.ValueOfInt32(int32(nsec)))
|
||||||
|
return nil
|
||||||
|
case "Timestamp":
|
||||||
|
v, err := unquoteString(string(in))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t, err := time.Parse(time.RFC3339Nano, v)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("bad Timestamp: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sec := t.Unix()
|
||||||
|
nsec := t.Nanosecond()
|
||||||
|
m.Set(fds.ByNumber(1), protoreflect.ValueOfInt64(int64(sec)))
|
||||||
|
m.Set(fds.ByNumber(2), protoreflect.ValueOfInt32(int32(nsec)))
|
||||||
|
return nil
|
||||||
|
case "Value":
|
||||||
|
switch {
|
||||||
|
case string(in) == "null":
|
||||||
|
m.Set(fds.ByNumber(1), protoreflect.ValueOfEnum(0))
|
||||||
|
case string(in) == "true":
|
||||||
|
m.Set(fds.ByNumber(4), protoreflect.ValueOfBool(true))
|
||||||
|
case string(in) == "false":
|
||||||
|
m.Set(fds.ByNumber(4), protoreflect.ValueOfBool(false))
|
||||||
|
case hasPrefixAndSuffix('"', in, '"'):
|
||||||
|
s, err := unquoteString(string(in))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unrecognized type for Value %q", in)
|
||||||
|
}
|
||||||
|
m.Set(fds.ByNumber(3), protoreflect.ValueOfString(s))
|
||||||
|
case hasPrefixAndSuffix('[', in, ']'):
|
||||||
|
v := m.Mutable(fds.ByNumber(6))
|
||||||
|
return u.unmarshalMessage(v.Message(), in)
|
||||||
|
case hasPrefixAndSuffix('{', in, '}'):
|
||||||
|
v := m.Mutable(fds.ByNumber(5))
|
||||||
|
return u.unmarshalMessage(v.Message(), in)
|
||||||
|
default:
|
||||||
|
f, err := strconv.ParseFloat(string(in), 0)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unrecognized type for Value %q", in)
|
||||||
|
}
|
||||||
|
m.Set(fds.ByNumber(2), protoreflect.ValueOfFloat64(f))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case "ListValue":
|
||||||
|
var jsonArray []json.RawMessage
|
||||||
|
if err := json.Unmarshal(in, &jsonArray); err != nil {
|
||||||
|
return fmt.Errorf("bad ListValue: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
lv := m.Mutable(fds.ByNumber(1)).List()
|
||||||
|
for _, raw := range jsonArray {
|
||||||
|
ve := lv.NewElement()
|
||||||
|
if err := u.unmarshalMessage(ve.Message(), raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
lv.Append(ve)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case "Struct":
|
||||||
|
var jsonObject map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(in, &jsonObject); err != nil {
|
||||||
|
return fmt.Errorf("bad StructValue: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mv := m.Mutable(fds.ByNumber(1)).Map()
|
||||||
|
for key, raw := range jsonObject {
|
||||||
|
kv := protoreflect.ValueOf(key).MapKey()
|
||||||
|
vv := mv.NewValue()
|
||||||
|
if err := u.unmarshalMessage(vv.Message(), raw); err != nil {
|
||||||
|
return fmt.Errorf("bad value in StructValue for key %q: %v", key, err)
|
||||||
|
}
|
||||||
|
mv.Set(kv, vv)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var jsonObject map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(in, &jsonObject); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle known fields.
|
||||||
|
for i := 0; i < fds.Len(); i++ {
|
||||||
|
fd := fds.Get(i)
|
||||||
|
if fd.IsWeak() && fd.Message().IsPlaceholder() {
|
||||||
|
continue // weak reference is not linked in
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for any raw JSON value associated with this field.
|
||||||
|
var raw json.RawMessage
|
||||||
|
name := string(fd.Name())
|
||||||
|
if fd.Kind() == protoreflect.GroupKind {
|
||||||
|
name = string(fd.Message().Name())
|
||||||
|
}
|
||||||
|
if v, ok := jsonObject[name]; ok {
|
||||||
|
delete(jsonObject, name)
|
||||||
|
raw = v
|
||||||
|
}
|
||||||
|
name = string(fd.JSONName())
|
||||||
|
if v, ok := jsonObject[name]; ok {
|
||||||
|
delete(jsonObject, name)
|
||||||
|
raw = v
|
||||||
|
}
|
||||||
|
|
||||||
|
field := m.NewField(fd)
|
||||||
|
// Unmarshal the field value.
|
||||||
|
if raw == nil || (string(raw) == "null" && !isSingularWellKnownValue(fd) && !isSingularJSONPBUnmarshaler(field, fd)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
v, err := u.unmarshalValue(field, raw, fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.Set(fd, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle extension fields.
|
||||||
|
for name, raw := range jsonObject {
|
||||||
|
if !strings.HasPrefix(name, "[") || !strings.HasSuffix(name, "]") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve the extension field by name.
|
||||||
|
xname := protoreflect.FullName(name[len("[") : len(name)-len("]")])
|
||||||
|
xt, _ := protoregistry.GlobalTypes.FindExtensionByName(xname)
|
||||||
|
if xt == nil && isMessageSet(md) {
|
||||||
|
xt, _ = protoregistry.GlobalTypes.FindExtensionByName(xname.Append("message_set_extension"))
|
||||||
|
}
|
||||||
|
if xt == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
delete(jsonObject, name)
|
||||||
|
fd := xt.TypeDescriptor()
|
||||||
|
if fd.ContainingMessage().FullName() != m.Descriptor().FullName() {
|
||||||
|
return fmt.Errorf("extension field %q does not extend message %q", xname, m.Descriptor().FullName())
|
||||||
|
}
|
||||||
|
|
||||||
|
field := m.NewField(fd)
|
||||||
|
// Unmarshal the field value.
|
||||||
|
if raw == nil || (string(raw) == "null" && !isSingularWellKnownValue(fd) && !isSingularJSONPBUnmarshaler(field, fd)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
v, err := u.unmarshalValue(field, raw, fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.Set(fd, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !u.AllowUnknownFields && len(jsonObject) > 0 {
|
||||||
|
for name := range jsonObject {
|
||||||
|
return fmt.Errorf("unknown field %q in %v", name, md.FullName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSingularWellKnownValue(fd protoreflect.FieldDescriptor) bool {
|
||||||
|
if fd.Cardinality() == protoreflect.Repeated {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if md := fd.Message(); md != nil {
|
||||||
|
return md.FullName() == "google.protobuf.Value"
|
||||||
|
}
|
||||||
|
if ed := fd.Enum(); ed != nil {
|
||||||
|
return ed.FullName() == "google.protobuf.NullValue"
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSingularJSONPBUnmarshaler(v protoreflect.Value, fd protoreflect.FieldDescriptor) bool {
|
||||||
|
if fd.Message() != nil && fd.Cardinality() != protoreflect.Repeated {
|
||||||
|
_, ok := proto.MessageV1(v.Interface()).(JSONPBUnmarshaler)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unmarshaler) unmarshalValue(v protoreflect.Value, in []byte, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
|
||||||
|
switch {
|
||||||
|
case fd.IsList():
|
||||||
|
var jsonArray []json.RawMessage
|
||||||
|
if err := json.Unmarshal(in, &jsonArray); err != nil {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
lv := v.List()
|
||||||
|
for _, raw := range jsonArray {
|
||||||
|
ve, err := u.unmarshalSingularValue(lv.NewElement(), raw, fd)
|
||||||
|
if err != nil {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
lv.Append(ve)
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
case fd.IsMap():
|
||||||
|
var jsonObject map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(in, &jsonObject); err != nil {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
kfd := fd.MapKey()
|
||||||
|
vfd := fd.MapValue()
|
||||||
|
mv := v.Map()
|
||||||
|
for key, raw := range jsonObject {
|
||||||
|
var kv protoreflect.MapKey
|
||||||
|
if kfd.Kind() == protoreflect.StringKind {
|
||||||
|
kv = protoreflect.ValueOf(key).MapKey()
|
||||||
|
} else {
|
||||||
|
v, err := u.unmarshalSingularValue(kfd.Default(), []byte(key), kfd)
|
||||||
|
if err != nil {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
kv = v.MapKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
vv, err := u.unmarshalSingularValue(mv.NewValue(), raw, vfd)
|
||||||
|
if err != nil {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
mv.Set(kv, vv)
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
default:
|
||||||
|
return u.unmarshalSingularValue(v, in, fd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var nonFinite = map[string]float64{
|
||||||
|
`"NaN"`: math.NaN(),
|
||||||
|
`"Infinity"`: math.Inf(+1),
|
||||||
|
`"-Infinity"`: math.Inf(-1),
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unmarshaler) unmarshalSingularValue(v protoreflect.Value, in []byte, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
|
||||||
|
switch fd.Kind() {
|
||||||
|
case protoreflect.BoolKind:
|
||||||
|
return unmarshalValue(in, new(bool))
|
||||||
|
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
|
||||||
|
return unmarshalValue(trimQuote(in), new(int32))
|
||||||
|
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
|
||||||
|
return unmarshalValue(trimQuote(in), new(int64))
|
||||||
|
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
|
||||||
|
return unmarshalValue(trimQuote(in), new(uint32))
|
||||||
|
case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
|
||||||
|
return unmarshalValue(trimQuote(in), new(uint64))
|
||||||
|
case protoreflect.FloatKind:
|
||||||
|
if f, ok := nonFinite[string(in)]; ok {
|
||||||
|
return protoreflect.ValueOfFloat32(float32(f)), nil
|
||||||
|
}
|
||||||
|
return unmarshalValue(trimQuote(in), new(float32))
|
||||||
|
case protoreflect.DoubleKind:
|
||||||
|
if f, ok := nonFinite[string(in)]; ok {
|
||||||
|
return protoreflect.ValueOfFloat64(float64(f)), nil
|
||||||
|
}
|
||||||
|
return unmarshalValue(trimQuote(in), new(float64))
|
||||||
|
case protoreflect.StringKind:
|
||||||
|
return unmarshalValue(in, new(string))
|
||||||
|
case protoreflect.BytesKind:
|
||||||
|
return unmarshalValue(in, new([]byte))
|
||||||
|
case protoreflect.EnumKind:
|
||||||
|
if hasPrefixAndSuffix('"', in, '"') {
|
||||||
|
vd := fd.Enum().Values().ByName(protoreflect.Name(trimQuote(in)))
|
||||||
|
if vd == nil {
|
||||||
|
return v, fmt.Errorf("unknown value %q for enum %s", in, fd.Enum().FullName())
|
||||||
|
}
|
||||||
|
return protoreflect.ValueOfEnum(vd.Number()), nil
|
||||||
|
}
|
||||||
|
return unmarshalValue(in, new(protoreflect.EnumNumber))
|
||||||
|
case protoreflect.MessageKind, protoreflect.GroupKind:
|
||||||
|
err := u.unmarshalMessage(v.Message(), in)
|
||||||
|
return v, err
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("invalid kind %v", fd.Kind()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalValue(in []byte, v interface{}) (protoreflect.Value, error) {
|
||||||
|
err := json.Unmarshal(in, v)
|
||||||
|
return protoreflect.ValueOf(reflect.ValueOf(v).Elem().Interface()), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func unquoteString(in string) (out string, err error) {
|
||||||
|
err = json.Unmarshal([]byte(in), &out)
|
||||||
|
return out, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasPrefixAndSuffix(prefix byte, in []byte, suffix byte) bool {
|
||||||
|
if len(in) >= 2 && in[0] == prefix && in[len(in)-1] == suffix {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// trimQuote is like unquoteString but simply strips surrounding quotes.
|
||||||
|
// This is incorrect, but is behavior done by the legacy implementation.
|
||||||
|
func trimQuote(in []byte) []byte {
|
||||||
|
if len(in) >= 2 && in[0] == '"' && in[len(in)-1] == '"' {
|
||||||
|
in = in[1 : len(in)-1]
|
||||||
|
}
|
||||||
|
return in
|
||||||
|
}
|
559
pkg/golang-protobuf/jsonpb/encode.go
Normal file
559
pkg/golang-protobuf/jsonpb/encode.go
Normal file
|
@ -0,0 +1,559 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package jsonpb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
|
protoV2 "google.golang.org/protobuf/proto"
|
||||||
|
"google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
"google.golang.org/protobuf/reflect/protoregistry"
|
||||||
|
)
|
||||||
|
|
||||||
|
const wrapJSONMarshalV2 = false
|
||||||
|
|
||||||
|
// Marshaler is a configurable object for marshaling protocol buffer messages
|
||||||
|
// to the specified JSON representation.
|
||||||
|
type Marshaler struct {
|
||||||
|
// OrigName specifies whether to use the original protobuf name for fields.
|
||||||
|
OrigName bool
|
||||||
|
|
||||||
|
// EnumsAsInts specifies whether to render enum values as integers,
|
||||||
|
// as opposed to string values.
|
||||||
|
EnumsAsInts bool
|
||||||
|
|
||||||
|
// EmitDefaults specifies whether to render fields with zero values.
|
||||||
|
EmitDefaults bool
|
||||||
|
|
||||||
|
// Indent controls whether the output is compact or not.
|
||||||
|
// If empty, the output is compact JSON. Otherwise, every JSON object
|
||||||
|
// entry and JSON array value will be on its own line.
|
||||||
|
// Each line will be preceded by repeated copies of Indent, where the
|
||||||
|
// number of copies is the current indentation depth.
|
||||||
|
Indent string
|
||||||
|
|
||||||
|
// AnyResolver is used to resolve the google.protobuf.Any well-known type.
|
||||||
|
// If unset, the global registry is used by default.
|
||||||
|
AnyResolver AnyResolver
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONPBMarshaler is implemented by protobuf messages that customize the
|
||||||
|
// way they are marshaled to JSON. Messages that implement this should also
|
||||||
|
// implement JSONPBUnmarshaler so that the custom format can be parsed.
|
||||||
|
//
|
||||||
|
// The JSON marshaling must follow the proto to JSON specification:
|
||||||
|
// https://developers.google.com/protocol-buffers/docs/proto3#json
|
||||||
|
//
|
||||||
|
// Deprecated: Custom types should implement protobuf reflection instead.
|
||||||
|
type JSONPBMarshaler interface {
|
||||||
|
MarshalJSONPB(*Marshaler) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal serializes a protobuf message as JSON into w.
|
||||||
|
func (jm *Marshaler) Marshal(w io.Writer, m proto.Message) error {
|
||||||
|
b, err := jm.marshal(m)
|
||||||
|
if len(b) > 0 {
|
||||||
|
if _, err := w.Write(b); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalToString serializes a protobuf message as JSON in string form.
|
||||||
|
func (jm *Marshaler) MarshalToString(m proto.Message) (string, error) {
|
||||||
|
b, err := jm.marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (jm *Marshaler) marshal(m proto.Message) ([]byte, error) {
|
||||||
|
v := reflect.ValueOf(m)
|
||||||
|
if m == nil || (v.Kind() == reflect.Ptr && v.IsNil()) {
|
||||||
|
return nil, errors.New("Marshal called with nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for custom marshalers first since they may not properly
|
||||||
|
// implement protobuf reflection that the logic below relies on.
|
||||||
|
if jsm, ok := m.(JSONPBMarshaler); ok {
|
||||||
|
return jsm.MarshalJSONPB(jm)
|
||||||
|
}
|
||||||
|
|
||||||
|
if wrapJSONMarshalV2 {
|
||||||
|
opts := protojson.MarshalOptions{
|
||||||
|
UseProtoNames: jm.OrigName,
|
||||||
|
UseEnumNumbers: jm.EnumsAsInts,
|
||||||
|
EmitUnpopulated: jm.EmitDefaults,
|
||||||
|
Indent: jm.Indent,
|
||||||
|
}
|
||||||
|
if jm.AnyResolver != nil {
|
||||||
|
opts.Resolver = anyResolver{jm.AnyResolver}
|
||||||
|
}
|
||||||
|
return opts.Marshal(proto.MessageReflect(m).Interface())
|
||||||
|
} else {
|
||||||
|
// Check for unpopulated required fields first.
|
||||||
|
m2 := proto.MessageReflect(m)
|
||||||
|
if err := protoV2.CheckInitialized(m2.Interface()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
w := jsonWriter{Marshaler: jm}
|
||||||
|
err := w.marshalMessage(m2, "", "")
|
||||||
|
return w.buf, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonWriter struct {
|
||||||
|
*Marshaler
|
||||||
|
buf []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *jsonWriter) write(s string) {
|
||||||
|
w.buf = append(w.buf, s...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *jsonWriter) marshalMessage(m protoreflect.Message, indent, typeURL string) error {
|
||||||
|
if jsm, ok := proto.MessageV1(m.Interface()).(JSONPBMarshaler); ok {
|
||||||
|
b, err := jsm.MarshalJSONPB(w.Marshaler)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if typeURL != "" {
|
||||||
|
// we are marshaling this object to an Any type
|
||||||
|
var js map[string]*json.RawMessage
|
||||||
|
if err = json.Unmarshal(b, &js); err != nil {
|
||||||
|
return fmt.Errorf("type %T produced invalid JSON: %v", m.Interface(), err)
|
||||||
|
}
|
||||||
|
turl, err := json.Marshal(typeURL)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to marshal type URL %q to JSON: %v", typeURL, err)
|
||||||
|
}
|
||||||
|
js["@type"] = (*json.RawMessage)(&turl)
|
||||||
|
if b, err = json.Marshal(js); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.write(string(b))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
md := m.Descriptor()
|
||||||
|
fds := md.Fields()
|
||||||
|
|
||||||
|
// Handle well-known types.
|
||||||
|
const secondInNanos = int64(time.Second / time.Nanosecond)
|
||||||
|
switch wellKnownType(md.FullName()) {
|
||||||
|
case "Any":
|
||||||
|
return w.marshalAny(m, indent)
|
||||||
|
case "BoolValue", "BytesValue", "StringValue",
|
||||||
|
"Int32Value", "UInt32Value", "FloatValue",
|
||||||
|
"Int64Value", "UInt64Value", "DoubleValue":
|
||||||
|
fd := fds.ByNumber(1)
|
||||||
|
return w.marshalValue(fd, m.Get(fd), indent)
|
||||||
|
case "Duration":
|
||||||
|
const maxSecondsInDuration = 315576000000
|
||||||
|
// "Generated output always contains 0, 3, 6, or 9 fractional digits,
|
||||||
|
// depending on required precision."
|
||||||
|
s := m.Get(fds.ByNumber(1)).Int()
|
||||||
|
ns := m.Get(fds.ByNumber(2)).Int()
|
||||||
|
if s < -maxSecondsInDuration || s > maxSecondsInDuration {
|
||||||
|
return fmt.Errorf("seconds out of range %v", s)
|
||||||
|
}
|
||||||
|
if ns <= -secondInNanos || ns >= secondInNanos {
|
||||||
|
return fmt.Errorf("ns out of range (%v, %v)", -secondInNanos, secondInNanos)
|
||||||
|
}
|
||||||
|
if (s > 0 && ns < 0) || (s < 0 && ns > 0) {
|
||||||
|
return errors.New("signs of seconds and nanos do not match")
|
||||||
|
}
|
||||||
|
var sign string
|
||||||
|
if s < 0 || ns < 0 {
|
||||||
|
sign, s, ns = "-", -1*s, -1*ns
|
||||||
|
}
|
||||||
|
x := fmt.Sprintf("%s%d.%09d", sign, s, ns)
|
||||||
|
x = strings.TrimSuffix(x, "000")
|
||||||
|
x = strings.TrimSuffix(x, "000")
|
||||||
|
x = strings.TrimSuffix(x, ".000")
|
||||||
|
w.write(fmt.Sprintf(`"%vs"`, x))
|
||||||
|
return nil
|
||||||
|
case "Timestamp":
|
||||||
|
// "RFC 3339, where generated output will always be Z-normalized
|
||||||
|
// and uses 0, 3, 6 or 9 fractional digits."
|
||||||
|
s := m.Get(fds.ByNumber(1)).Int()
|
||||||
|
ns := m.Get(fds.ByNumber(2)).Int()
|
||||||
|
if ns < 0 || ns >= secondInNanos {
|
||||||
|
return fmt.Errorf("ns out of range [0, %v)", secondInNanos)
|
||||||
|
}
|
||||||
|
t := time.Unix(s, ns).UTC()
|
||||||
|
// time.RFC3339Nano isn't exactly right (we need to get 3/6/9 fractional digits).
|
||||||
|
x := t.Format("2006-01-02T15:04:05.000000000")
|
||||||
|
x = strings.TrimSuffix(x, "000")
|
||||||
|
x = strings.TrimSuffix(x, "000")
|
||||||
|
x = strings.TrimSuffix(x, ".000")
|
||||||
|
w.write(fmt.Sprintf(`"%vZ"`, x))
|
||||||
|
return nil
|
||||||
|
case "Value":
|
||||||
|
// JSON value; which is a null, number, string, bool, object, or array.
|
||||||
|
od := md.Oneofs().Get(0)
|
||||||
|
fd := m.WhichOneof(od)
|
||||||
|
if fd == nil {
|
||||||
|
return errors.New("nil Value")
|
||||||
|
}
|
||||||
|
return w.marshalValue(fd, m.Get(fd), indent)
|
||||||
|
case "Struct", "ListValue":
|
||||||
|
// JSON object or array.
|
||||||
|
fd := fds.ByNumber(1)
|
||||||
|
return w.marshalValue(fd, m.Get(fd), indent)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.write("{")
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
firstField := true
|
||||||
|
if typeURL != "" {
|
||||||
|
if err := w.marshalTypeURL(indent, typeURL); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
firstField = false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < fds.Len(); {
|
||||||
|
fd := fds.Get(i)
|
||||||
|
if od := fd.ContainingOneof(); od != nil {
|
||||||
|
fd = m.WhichOneof(od)
|
||||||
|
i += od.Fields().Len()
|
||||||
|
if fd == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
v := m.Get(fd)
|
||||||
|
|
||||||
|
if !m.Has(fd) {
|
||||||
|
if !w.EmitDefaults || fd.ContainingOneof() != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if fd.Cardinality() != protoreflect.Repeated && (fd.Message() != nil || fd.Syntax() == protoreflect.Proto2) {
|
||||||
|
v = protoreflect.Value{} // use "null" for singular messages or proto2 scalars
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !firstField {
|
||||||
|
w.writeComma()
|
||||||
|
}
|
||||||
|
if err := w.marshalField(fd, v, indent); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
firstField = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle proto2 extensions.
|
||||||
|
if md.ExtensionRanges().Len() > 0 {
|
||||||
|
// Collect a sorted list of all extension descriptor and values.
|
||||||
|
type ext struct {
|
||||||
|
desc protoreflect.FieldDescriptor
|
||||||
|
val protoreflect.Value
|
||||||
|
}
|
||||||
|
var exts []ext
|
||||||
|
m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
|
||||||
|
if fd.IsExtension() {
|
||||||
|
exts = append(exts, ext{fd, v})
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
sort.Slice(exts, func(i, j int) bool {
|
||||||
|
return exts[i].desc.Number() < exts[j].desc.Number()
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, ext := range exts {
|
||||||
|
if !firstField {
|
||||||
|
w.writeComma()
|
||||||
|
}
|
||||||
|
if err := w.marshalField(ext.desc, ext.val, indent); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
firstField = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write("\n")
|
||||||
|
w.write(indent)
|
||||||
|
}
|
||||||
|
w.write("}")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *jsonWriter) writeComma() {
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write(",\n")
|
||||||
|
} else {
|
||||||
|
w.write(",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *jsonWriter) marshalAny(m protoreflect.Message, indent string) error {
|
||||||
|
// "If the Any contains a value that has a special JSON mapping,
|
||||||
|
// it will be converted as follows: {"@type": xxx, "value": yyy}.
|
||||||
|
// Otherwise, the value will be converted into a JSON object,
|
||||||
|
// and the "@type" field will be inserted to indicate the actual data type."
|
||||||
|
md := m.Descriptor()
|
||||||
|
typeURL := m.Get(md.Fields().ByNumber(1)).String()
|
||||||
|
rawVal := m.Get(md.Fields().ByNumber(2)).Bytes()
|
||||||
|
|
||||||
|
var m2 protoreflect.Message
|
||||||
|
if w.AnyResolver != nil {
|
||||||
|
mi, err := w.AnyResolver.Resolve(typeURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m2 = proto.MessageReflect(mi)
|
||||||
|
} else {
|
||||||
|
mt, err := protoregistry.GlobalTypes.FindMessageByURL(typeURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m2 = mt.New()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := protoV2.Unmarshal(rawVal, m2.Interface()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if wellKnownType(m2.Descriptor().FullName()) == "" {
|
||||||
|
return w.marshalMessage(m2, indent, typeURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.write("{")
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write("\n")
|
||||||
|
}
|
||||||
|
if err := w.marshalTypeURL(indent, typeURL); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.writeComma()
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write(indent)
|
||||||
|
w.write(w.Indent)
|
||||||
|
w.write(`"value": `)
|
||||||
|
} else {
|
||||||
|
w.write(`"value":`)
|
||||||
|
}
|
||||||
|
if err := w.marshalMessage(m2, indent+w.Indent, ""); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write("\n")
|
||||||
|
w.write(indent)
|
||||||
|
}
|
||||||
|
w.write("}")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *jsonWriter) marshalTypeURL(indent, typeURL string) error {
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write(indent)
|
||||||
|
w.write(w.Indent)
|
||||||
|
}
|
||||||
|
w.write(`"@type":`)
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write(" ")
|
||||||
|
}
|
||||||
|
b, err := json.Marshal(typeURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.write(string(b))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshalField writes field description and value to the Writer.
|
||||||
|
func (w *jsonWriter) marshalField(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error {
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write(indent)
|
||||||
|
w.write(w.Indent)
|
||||||
|
}
|
||||||
|
w.write(`"`)
|
||||||
|
switch {
|
||||||
|
case fd.IsExtension():
|
||||||
|
// For message set, use the fname of the message as the extension name.
|
||||||
|
name := string(fd.FullName())
|
||||||
|
if isMessageSet(fd.ContainingMessage()) {
|
||||||
|
name = strings.TrimSuffix(name, ".message_set_extension")
|
||||||
|
}
|
||||||
|
|
||||||
|
w.write("[" + name + "]")
|
||||||
|
case w.OrigName:
|
||||||
|
name := string(fd.Name())
|
||||||
|
if fd.Kind() == protoreflect.GroupKind {
|
||||||
|
name = string(fd.Message().Name())
|
||||||
|
}
|
||||||
|
w.write(name)
|
||||||
|
default:
|
||||||
|
w.write(string(fd.JSONName()))
|
||||||
|
}
|
||||||
|
w.write(`":`)
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write(" ")
|
||||||
|
}
|
||||||
|
return w.marshalValue(fd, v, indent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *jsonWriter) marshalValue(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error {
|
||||||
|
switch {
|
||||||
|
case fd.IsList():
|
||||||
|
w.write("[")
|
||||||
|
comma := ""
|
||||||
|
lv := v.List()
|
||||||
|
for i := 0; i < lv.Len(); i++ {
|
||||||
|
w.write(comma)
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write("\n")
|
||||||
|
w.write(indent)
|
||||||
|
w.write(w.Indent)
|
||||||
|
w.write(w.Indent)
|
||||||
|
}
|
||||||
|
if err := w.marshalSingularValue(fd, lv.Get(i), indent+w.Indent); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
comma = ","
|
||||||
|
}
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write("\n")
|
||||||
|
w.write(indent)
|
||||||
|
w.write(w.Indent)
|
||||||
|
}
|
||||||
|
w.write("]")
|
||||||
|
return nil
|
||||||
|
case fd.IsMap():
|
||||||
|
kfd := fd.MapKey()
|
||||||
|
vfd := fd.MapValue()
|
||||||
|
mv := v.Map()
|
||||||
|
|
||||||
|
// Collect a sorted list of all map keys and values.
|
||||||
|
type entry struct{ key, val protoreflect.Value }
|
||||||
|
var entries []entry
|
||||||
|
mv.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
|
||||||
|
entries = append(entries, entry{k.Value(), v})
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
sort.Slice(entries, func(i, j int) bool {
|
||||||
|
switch kfd.Kind() {
|
||||||
|
case protoreflect.BoolKind:
|
||||||
|
return !entries[i].key.Bool() && entries[j].key.Bool()
|
||||||
|
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
|
||||||
|
return entries[i].key.Int() < entries[j].key.Int()
|
||||||
|
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
|
||||||
|
return entries[i].key.Uint() < entries[j].key.Uint()
|
||||||
|
case protoreflect.StringKind:
|
||||||
|
return entries[i].key.String() < entries[j].key.String()
|
||||||
|
default:
|
||||||
|
panic("invalid kind")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
w.write(`{`)
|
||||||
|
comma := ""
|
||||||
|
for _, entry := range entries {
|
||||||
|
w.write(comma)
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write("\n")
|
||||||
|
w.write(indent)
|
||||||
|
w.write(w.Indent)
|
||||||
|
w.write(w.Indent)
|
||||||
|
}
|
||||||
|
|
||||||
|
s := fmt.Sprint(entry.key.Interface())
|
||||||
|
b, err := json.Marshal(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.write(string(b))
|
||||||
|
|
||||||
|
w.write(`:`)
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write(` `)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := w.marshalSingularValue(vfd, entry.val, indent+w.Indent); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
comma = ","
|
||||||
|
}
|
||||||
|
if w.Indent != "" {
|
||||||
|
w.write("\n")
|
||||||
|
w.write(indent)
|
||||||
|
w.write(w.Indent)
|
||||||
|
}
|
||||||
|
w.write(`}`)
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return w.marshalSingularValue(fd, v, indent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *jsonWriter) marshalSingularValue(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error {
|
||||||
|
switch {
|
||||||
|
case !v.IsValid():
|
||||||
|
w.write("null")
|
||||||
|
return nil
|
||||||
|
case fd.Message() != nil:
|
||||||
|
return w.marshalMessage(v.Message(), indent+w.Indent, "")
|
||||||
|
case fd.Enum() != nil:
|
||||||
|
if fd.Enum().FullName() == "google.protobuf.NullValue" {
|
||||||
|
w.write("null")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
vd := fd.Enum().Values().ByNumber(v.Enum())
|
||||||
|
if vd == nil || w.EnumsAsInts {
|
||||||
|
w.write(strconv.Itoa(int(v.Enum())))
|
||||||
|
} else {
|
||||||
|
w.write(`"` + string(vd.Name()) + `"`)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
switch v.Interface().(type) {
|
||||||
|
case float32, float64:
|
||||||
|
switch {
|
||||||
|
case math.IsInf(v.Float(), +1):
|
||||||
|
w.write(`"Infinity"`)
|
||||||
|
return nil
|
||||||
|
case math.IsInf(v.Float(), -1):
|
||||||
|
w.write(`"-Infinity"`)
|
||||||
|
return nil
|
||||||
|
case math.IsNaN(v.Float()):
|
||||||
|
w.write(`"NaN"`)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case int64, uint64:
|
||||||
|
w.write(fmt.Sprintf(`"%d"`, v.Interface()))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := json.Marshal(v.Interface())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.write(string(b))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
69
pkg/golang-protobuf/jsonpb/json.go
Normal file
69
pkg/golang-protobuf/jsonpb/json.go
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package jsonpb provides functionality to marshal and unmarshal between a
|
||||||
|
// protocol buffer message and JSON. It follows the specification at
|
||||||
|
// https://developers.google.com/protocol-buffers/docs/proto3#json.
|
||||||
|
//
|
||||||
|
// Do not rely on the default behavior of the standard encoding/json package
|
||||||
|
// when called on generated message types as it does not operate correctly.
|
||||||
|
//
|
||||||
|
// Deprecated: Use the "google.golang.org/protobuf/encoding/protojson"
|
||||||
|
// package instead.
|
||||||
|
package jsonpb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
"google.golang.org/protobuf/reflect/protoregistry"
|
||||||
|
"google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AnyResolver takes a type URL, present in an Any message,
|
||||||
|
// and resolves it into an instance of the associated message.
|
||||||
|
type AnyResolver interface {
|
||||||
|
Resolve(typeURL string) (proto.Message, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type anyResolver struct{ AnyResolver }
|
||||||
|
|
||||||
|
func (r anyResolver) FindMessageByName(message protoreflect.FullName) (protoreflect.MessageType, error) {
|
||||||
|
return r.FindMessageByURL(string(message))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r anyResolver) FindMessageByURL(url string) (protoreflect.MessageType, error) {
|
||||||
|
m, err := r.Resolve(url)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return protoimpl.X.MessageTypeOf(m), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r anyResolver) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) {
|
||||||
|
return protoregistry.GlobalTypes.FindExtensionByName(field)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r anyResolver) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) {
|
||||||
|
return protoregistry.GlobalTypes.FindExtensionByNumber(message, field)
|
||||||
|
}
|
||||||
|
|
||||||
|
func wellKnownType(s protoreflect.FullName) string {
|
||||||
|
if s.Parent() == "google.protobuf" {
|
||||||
|
switch s.Name() {
|
||||||
|
case "Empty", "Any",
|
||||||
|
"BoolValue", "BytesValue", "StringValue",
|
||||||
|
"Int32Value", "UInt32Value", "FloatValue",
|
||||||
|
"Int64Value", "UInt64Value", "DoubleValue",
|
||||||
|
"Duration", "Timestamp",
|
||||||
|
"NullValue", "Struct", "Value", "ListValue":
|
||||||
|
return string(s.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func isMessageSet(md protoreflect.MessageDescriptor) bool {
|
||||||
|
ms, ok := md.(interface{ IsMessageSet() bool })
|
||||||
|
return ok && ms.IsMessageSet()
|
||||||
|
}
|
1264
pkg/golang-protobuf/jsonpb/json_test.go
Normal file
1264
pkg/golang-protobuf/jsonpb/json_test.go
Normal file
File diff suppressed because it is too large
Load diff
|
@ -26,3 +26,5 @@ require (
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/golang/protobuf => ../../../pkg/golang-protobuf
|
replace github.com/golang/protobuf => ../../../pkg/golang-protobuf
|
||||||
|
|
||||||
|
replace github.com/golang/protobuf/jsonpb => ../../../pkg/golang-protobuf/jsonpb
|
||||||
|
|
Loading…
Reference in a new issue