blob: f79b4ac8edb2a69cb5f467a5a9714dd3fc070216 [file] [log] [blame]
package dynamic
// JSON marshalling and unmarshalling for dynamic messages
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"math"
"reflect"
"sort"
"strconv"
"strings"
"github.com/golang/protobuf/jsonpb"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/protoc-gen-go/descriptor"
// link in the well-known-types that have a special JSON format
_ "github.com/golang/protobuf/ptypes/any"
_ "github.com/golang/protobuf/ptypes/duration"
_ "github.com/golang/protobuf/ptypes/empty"
_ "github.com/golang/protobuf/ptypes/struct"
_ "github.com/golang/protobuf/ptypes/timestamp"
_ "github.com/golang/protobuf/ptypes/wrappers"
"github.com/jhump/protoreflect/desc"
)
var wellKnownTypeNames = map[string]struct{}{
"google.protobuf.Any": {},
"google.protobuf.Empty": {},
"google.protobuf.Duration": {},
"google.protobuf.Timestamp": {},
// struct.proto
"google.protobuf.Struct": {},
"google.protobuf.Value": {},
"google.protobuf.ListValue": {},
// wrappers.proto
"google.protobuf.DoubleValue": {},
"google.protobuf.FloatValue": {},
"google.protobuf.Int64Value": {},
"google.protobuf.UInt64Value": {},
"google.protobuf.Int32Value": {},
"google.protobuf.UInt32Value": {},
"google.protobuf.BoolValue": {},
"google.protobuf.StringValue": {},
"google.protobuf.BytesValue": {},
}
// MarshalJSON serializes this message to bytes in JSON format, returning an
// error if the operation fails. The resulting bytes will be a valid UTF8
// string.
//
// This method uses a compact form: no newlines, and spaces between fields and
// between field identifiers and values are elided.
//
// This method is convenient shorthand for invoking MarshalJSONPB with a default
// (zero value) marshaler:
//
// m.MarshalJSONPB(&jsonpb.Marshaler{})
//
// So enums are serialized using enum value name strings, and values that are
// not present (including those with default/zero value for messages defined in
// "proto3" syntax) are omitted.
func (m *Message) MarshalJSON() ([]byte, error) {
return m.MarshalJSONPB(&jsonpb.Marshaler{})
}
// MarshalJSONIndent serializes this message to bytes in JSON format, returning
// an error if the operation fails. The resulting bytes will be a valid UTF8
// string.
//
// This method uses a "pretty-printed" form, with each field on its own line and
// spaces between field identifiers and values. Indentation of two spaces is
// used.
//
// This method is convenient shorthand for invoking MarshalJSONPB with a default
// (zero value) marshaler:
//
// m.MarshalJSONPB(&jsonpb.Marshaler{Indent: " "})
//
// So enums are serialized using enum value name strings, and values that are
// not present (including those with default/zero value for messages defined in
// "proto3" syntax) are omitted.
func (m *Message) MarshalJSONIndent() ([]byte, error) {
return m.MarshalJSONPB(&jsonpb.Marshaler{Indent: " "})
}
// MarshalJSONPB serializes this message to bytes in JSON format, returning an
// error if the operation fails. The resulting bytes will be a valid UTF8
// string. The given marshaler is used to convey options used during marshaling.
//
// If this message contains nested messages that are generated message types (as
// opposed to dynamic messages), the given marshaler is used to marshal it.
//
// When marshaling any nested messages, any jsonpb.AnyResolver configured in the
// given marshaler is augmented with knowledge of message types known to this
// message's descriptor (and its enclosing file and set of transitive
// dependencies).
func (m *Message) MarshalJSONPB(opts *jsonpb.Marshaler) ([]byte, error) {
var b indentBuffer
b.indent = opts.Indent
if len(opts.Indent) == 0 {
b.indentCount = -1
}
b.comma = true
if err := m.marshalJSON(&b, opts); err != nil {
return nil, err
}
return b.Bytes(), nil
}
func (m *Message) marshalJSON(b *indentBuffer, opts *jsonpb.Marshaler) error {
if r, changed := wrapResolver(opts.AnyResolver, m.mf, m.md.GetFile()); changed {
newOpts := *opts
newOpts.AnyResolver = r
opts = &newOpts
}
if ok, err := marshalWellKnownType(m, b, opts); ok {
return err
}
err := b.WriteByte('{')
if err != nil {
return err
}
err = b.start()
if err != nil {
return err
}
var tags []int
if opts.EmitDefaults {
tags = m.allKnownFieldTags()
} else {
tags = m.knownFieldTags()
}
first := true
for _, tag := range tags {
itag := int32(tag)
fd := m.FindFieldDescriptor(itag)
v, ok := m.values[itag]
if !ok {
if fd.GetOneOf() != nil {
// don't print defaults for fields in a oneof
continue
}
v = fd.GetDefaultValue()
}
err := b.maybeNext(&first)
if err != nil {
return err
}
err = marshalKnownFieldJSON(b, fd, v, opts)
if err != nil {
return err
}
}
err = b.end()
if err != nil {
return err
}
err = b.WriteByte('}')
if err != nil {
return err
}
return nil
}
func marshalWellKnownType(m *Message, b *indentBuffer, opts *jsonpb.Marshaler) (bool, error) {
fqn := m.md.GetFullyQualifiedName()
if _, ok := wellKnownTypeNames[fqn]; !ok {
return false, nil
}
msgType := proto.MessageType(fqn)
if msgType == nil {
// wtf?
panic(fmt.Sprintf("could not find registered message type for %q", fqn))
}
// convert dynamic message to well-known type and let jsonpb marshal it
msg := reflect.New(msgType.Elem()).Interface().(proto.Message)
if err := m.MergeInto(msg); err != nil {
return true, err
}
return true, opts.Marshal(b, msg)
}
func marshalKnownFieldJSON(b *indentBuffer, fd *desc.FieldDescriptor, v interface{}, opts *jsonpb.Marshaler) error {
var jsonName string
if opts.OrigName {
jsonName = fd.GetName()
} else {
jsonName = fd.AsFieldDescriptorProto().GetJsonName()
if jsonName == "" {
jsonName = fd.GetName()
}
}
if fd.IsExtension() {
var scope string
switch parent := fd.GetParent().(type) {
case *desc.FileDescriptor:
scope = parent.GetPackage()
default:
scope = parent.GetFullyQualifiedName()
}
if scope == "" {
jsonName = fmt.Sprintf("[%s]", jsonName)
} else {
jsonName = fmt.Sprintf("[%s.%s]", scope, jsonName)
}
}
err := writeJsonString(b, jsonName)
if err != nil {
return err
}
err = b.sep()
if err != nil {
return err
}
if isNil(v) {
_, err := b.WriteString("null")
return err
}
if fd.IsMap() {
err = b.WriteByte('{')
if err != nil {
return err
}
err = b.start()
if err != nil {
return err
}
md := fd.GetMessageType()
vfd := md.FindFieldByNumber(2)
mp := v.(map[interface{}]interface{})
keys := make([]interface{}, 0, len(mp))
for k := range mp {
keys = append(keys, k)
}
sort.Sort(sortable(keys))
first := true
for _, mk := range keys {
mv := mp[mk]
err := b.maybeNext(&first)
if err != nil {
return err
}
err = marshalKnownFieldMapEntryJSON(b, mk, vfd, mv, opts)
if err != nil {
return err
}
}
err = b.end()
if err != nil {
return err
}
return b.WriteByte('}')
} else if fd.IsRepeated() {
err = b.WriteByte('[')
if err != nil {
return err
}
err = b.start()
if err != nil {
return err
}
sl := v.([]interface{})
first := true
for _, slv := range sl {
err := b.maybeNext(&first)
if err != nil {
return err
}
err = marshalKnownFieldValueJSON(b, fd, slv, opts)
if err != nil {
return err
}
}
err = b.end()
if err != nil {
return err
}
return b.WriteByte(']')
} else {
return marshalKnownFieldValueJSON(b, fd, v, opts)
}
}
func isNil(v interface{}) bool {
if v == nil {
return true
}
rv := reflect.ValueOf(v)
return rv.Kind() == reflect.Ptr && rv.IsNil()
}
func marshalKnownFieldMapEntryJSON(b *indentBuffer, mk interface{}, vfd *desc.FieldDescriptor, mv interface{}, opts *jsonpb.Marshaler) error {
rk := reflect.ValueOf(mk)
var strkey string
switch rk.Kind() {
case reflect.Bool:
strkey = strconv.FormatBool(rk.Bool())
case reflect.Int32, reflect.Int64:
strkey = strconv.FormatInt(rk.Int(), 10)
case reflect.Uint32, reflect.Uint64:
strkey = strconv.FormatUint(rk.Uint(), 10)
case reflect.String:
strkey = rk.String()
default:
return fmt.Errorf("invalid map key value: %v (%v)", mk, rk.Type())
}
err := writeString(b, strkey)
if err != nil {
return err
}
err = b.sep()
if err != nil {
return err
}
return marshalKnownFieldValueJSON(b, vfd, mv, opts)
}
func marshalKnownFieldValueJSON(b *indentBuffer, fd *desc.FieldDescriptor, v interface{}, opts *jsonpb.Marshaler) error {
rv := reflect.ValueOf(v)
switch rv.Kind() {
case reflect.Int32, reflect.Int64:
ed := fd.GetEnumType()
if !opts.EnumsAsInts && ed != nil {
n := int32(rv.Int())
vd := ed.FindValueByNumber(n)
if vd == nil {
_, err := b.WriteString(strconv.FormatInt(rv.Int(), 10))
return err
} else {
return writeJsonString(b, vd.GetName())
}
} else {
_, err := b.WriteString(strconv.FormatInt(rv.Int(), 10))
return err
}
case reflect.Uint32, reflect.Uint64:
_, err := b.WriteString(strconv.FormatUint(rv.Uint(), 10))
return err
case reflect.Float32, reflect.Float64:
f := rv.Float()
var str string
if math.IsNaN(f) {
str = `"NaN"`
} else if math.IsInf(f, 1) {
str = `"Infinity"`
} else if math.IsInf(f, -1) {
str = `"-Infinity"`
} else {
var bits int
if rv.Kind() == reflect.Float32 {
bits = 32
} else {
bits = 64
}
str = strconv.FormatFloat(rv.Float(), 'g', -1, bits)
}
_, err := b.WriteString(str)
return err
case reflect.Bool:
_, err := b.WriteString(strconv.FormatBool(rv.Bool()))
return err
case reflect.Slice:
bstr := base64.StdEncoding.EncodeToString(rv.Bytes())
return writeJsonString(b, bstr)
case reflect.String:
return writeJsonString(b, rv.String())
default:
// must be a message
if dm, ok := v.(*Message); ok {
return dm.marshalJSON(b, opts)
} else {
var err error
if b.indentCount <= 0 || len(b.indent) == 0 {
err = opts.Marshal(b, v.(proto.Message))
} else {
str, err := opts.MarshalToString(v.(proto.Message))
if err != nil {
return err
}
indent := strings.Repeat(b.indent, b.indentCount)
pos := 0
// add indention prefix to each line
for pos < len(str) {
start := pos
nextPos := strings.Index(str[pos:], "\n")
if nextPos == -1 {
nextPos = len(str)
} else {
nextPos = pos + nextPos + 1 // include newline
}
line := str[start:nextPos]
if pos > 0 {
_, err = b.WriteString(indent)
if err != nil {
return err
}
}
_, err = b.WriteString(line)
if err != nil {
return err
}
pos = nextPos
}
}
return err
}
}
}
func writeJsonString(b *indentBuffer, s string) error {
if sbytes, err := json.Marshal(s); err != nil {
return err
} else {
_, err := b.Write(sbytes)
return err
}
}
// UnmarshalJSON de-serializes the message that is present, in JSON format, in
// the given bytes into this message. It first resets the current message. It
// returns an error if the given bytes do not contain a valid encoding of this
// message type in JSON format.
//
// This method is shorthand for invoking UnmarshalJSONPB with a default (zero
// value) unmarshaler:
//
// m.UnmarshalMergeJSONPB(&jsonpb.Unmarshaler{}, js)
//
// So unknown fields will result in an error, and no provided jsonpb.AnyResolver
// will be used when parsing google.protobuf.Any messages.
func (m *Message) UnmarshalJSON(js []byte) error {
return m.UnmarshalJSONPB(&jsonpb.Unmarshaler{}, js)
}
// UnmarshalMergeJSON de-serializes the message that is present, in JSON format,
// in the given bytes into this message. Unlike UnmarshalJSON, it does not first
// reset the message, instead merging the data in the given bytes into the
// existing data in this message.
func (m *Message) UnmarshalMergeJSON(js []byte) error {
return m.UnmarshalMergeJSONPB(&jsonpb.Unmarshaler{}, js)
}
// UnmarshalJSONPB de-serializes the message that is present, in JSON format, in
// the given bytes into this message. The given unmarshaler conveys options used
// when parsing the JSON. This function first resets the current message. It
// returns an error if the given bytes do not contain a valid encoding of this
// message type in JSON format.
//
// The decoding is lenient:
// 1. The JSON can refer to fields either by their JSON name or by their
// declared name.
// 2. The JSON can use either numeric values or string names for enum values.
//
// When instantiating nested messages, if this message's associated factory
// returns a generated message type (as opposed to a dynamic message), the given
// unmarshaler is used to unmarshal it.
//
// When unmarshaling any nested messages, any jsonpb.AnyResolver configured in
// the given unmarshaler is augmented with knowledge of message types known to
// this message's descriptor (and its enclosing file and set of transitive
// dependencies).
func (m *Message) UnmarshalJSONPB(opts *jsonpb.Unmarshaler, js []byte) error {
m.Reset()
if err := m.UnmarshalMergeJSONPB(opts, js); err != nil {
return err
}
return m.Validate()
}
// UnmarshalMergeJSONPB de-serializes the message that is present, in JSON
// format, in the given bytes into this message. The given unmarshaler conveys
// options used when parsing the JSON. Unlike UnmarshalJSONPB, it does not first
// reset the message, instead merging the data in the given bytes into the
// existing data in this message.
func (m *Message) UnmarshalMergeJSONPB(opts *jsonpb.Unmarshaler, js []byte) error {
r := newJsReader(js)
err := m.unmarshalJson(r, opts)
if err != nil {
return err
}
if t, err := r.poll(); err != io.EOF {
b, _ := ioutil.ReadAll(r.unread())
s := fmt.Sprintf("%v%s", t, string(b))
return fmt.Errorf("superfluous data found after JSON object: %q", s)
}
return nil
}
func unmarshalWellKnownType(m *Message, r *jsReader, opts *jsonpb.Unmarshaler) (bool, error) {
fqn := m.md.GetFullyQualifiedName()
if _, ok := wellKnownTypeNames[fqn]; !ok {
return false, nil
}
msgType := proto.MessageType(fqn)
if msgType == nil {
// wtf?
panic(fmt.Sprintf("could not find registered message type for %q", fqn))
}
// extract json value from r
var js json.RawMessage
if err := json.NewDecoder(r.unread()).Decode(&js); err != nil {
return true, err
}
if err := r.skip(); err != nil {
return true, err
}
// unmarshal into well-known type and then convert to dynamic message
msg := reflect.New(msgType.Elem()).Interface().(proto.Message)
if err := opts.Unmarshal(bytes.NewReader(js), msg); err != nil {
return true, err
}
return true, m.MergeFrom(msg)
}
func (m *Message) unmarshalJson(r *jsReader, opts *jsonpb.Unmarshaler) error {
if r, changed := wrapResolver(opts.AnyResolver, m.mf, m.md.GetFile()); changed {
newOpts := *opts
newOpts.AnyResolver = r
opts = &newOpts
}
if ok, err := unmarshalWellKnownType(m, r, opts); ok {
return err
}
t, err := r.peek()
if err != nil {
return err
}
if t == nil {
// if json is simply "null" we do nothing
r.poll()
return nil
}
if err := r.beginObject(); err != nil {
return err
}
for r.hasNext() {
f, err := r.nextObjectKey()
if err != nil {
return err
}
fd := m.FindFieldDescriptorByJSONName(f)
if fd == nil {
if opts.AllowUnknownFields {
r.skip()
continue
}
return fmt.Errorf("message type %s has no known field named %s", m.md.GetFullyQualifiedName(), f)
}
v, err := unmarshalJsField(fd, r, m.mf, opts)
if err != nil {
return err
}
if v != nil {
if err := mergeField(m, fd, v); err != nil {
return err
}
} else if fd.GetOneOf() != nil {
// preserve explicit null for oneof fields (this is a little odd but
// mimics the behavior of jsonpb with oneofs in generated message types)
if fd.GetMessageType() != nil {
typ := m.mf.GetKnownTypeRegistry().GetKnownType(fd.GetMessageType().GetFullyQualifiedName())
if typ != nil {
// typed nil
if typ.Kind() != reflect.Ptr {
typ = reflect.PtrTo(typ)
}
v = reflect.Zero(typ).Interface()
} else {
// can't use nil dynamic message, so we just use empty one instead
v = m.mf.NewDynamicMessage(fd.GetMessageType())
}
if err := m.setField(fd, v); err != nil {
return err
}
} else {
// not a message... explicit null makes no sense
return fmt.Errorf("message type %s cannot set field %s to null: it is not a message type", m.md.GetFullyQualifiedName(), f)
}
} else {
m.clearField(fd)
}
}
if err := r.endObject(); err != nil {
return err
}
return nil
}
func isWellKnownValue(fd *desc.FieldDescriptor) bool {
return !fd.IsRepeated() && fd.GetType() == descriptor.FieldDescriptorProto_TYPE_MESSAGE &&
fd.GetMessageType().GetFullyQualifiedName() == "google.protobuf.Value"
}
func isWellKnownListValue(fd *desc.FieldDescriptor) bool {
return !fd.IsRepeated() && fd.GetType() == descriptor.FieldDescriptorProto_TYPE_MESSAGE &&
fd.GetMessageType().GetFullyQualifiedName() == "google.protobuf.ListValue"
}
func unmarshalJsField(fd *desc.FieldDescriptor, r *jsReader, mf *MessageFactory, opts *jsonpb.Unmarshaler) (interface{}, error) {
t, err := r.peek()
if err != nil {
return nil, err
}
if t == nil && !isWellKnownValue(fd) {
// if value is null, just return nil
// (unless field is google.protobuf.Value, in which case
// we fall through to parse it as an instance where its
// underlying value is set to a NullValue)
r.poll()
return nil, nil
}
if t == json.Delim('{') && fd.IsMap() {
entryType := fd.GetMessageType()
keyType := entryType.FindFieldByNumber(1)
valueType := entryType.FindFieldByNumber(2)
mp := map[interface{}]interface{}{}
// TODO: if there are just two map keys "key" and "value" and they have the right type of values,
// treat this JSON object as a single map entry message. (In keeping with support of map fields as
// if they were normal repeated field of entry messages as well as supporting a transition from
// optional to repeated...)
if err := r.beginObject(); err != nil {
return nil, err
}
for r.hasNext() {
kk, err := unmarshalJsFieldElement(keyType, r, mf, opts)
if err != nil {
return nil, err
}
vv, err := unmarshalJsFieldElement(valueType, r, mf, opts)
if err != nil {
return nil, err
}
mp[kk] = vv
}
if err := r.endObject(); err != nil {
return nil, err
}
return mp, nil
} else if t == json.Delim('[') && !isWellKnownListValue(fd) {
// We support parsing an array, even if field is not repeated, to mimic support in proto
// binary wire format that supports changing an optional field to repeated and vice versa.
// If the field is not repeated, we only keep the last value in the array.
if err := r.beginArray(); err != nil {
return nil, err
}
var sl []interface{}
var v interface{}
for r.hasNext() {
var err error
v, err = unmarshalJsFieldElement(fd, r, mf, opts)
if err != nil {
return nil, err
}
if fd.IsRepeated() && v != nil {
sl = append(sl, v)
}
}
if err := r.endArray(); err != nil {
return nil, err
}
if fd.IsMap() {
mp := map[interface{}]interface{}{}
for _, m := range sl {
msg := m.(*Message)
kk, err := msg.TryGetFieldByNumber(1)
if err != nil {
return nil, err
}
vv, err := msg.TryGetFieldByNumber(2)
if err != nil {
return nil, err
}
mp[kk] = vv
}
return mp, nil
} else if fd.IsRepeated() {
return sl, nil
} else {
return v, nil
}
} else {
// We support parsing a singular value, even if field is repeated, to mimic support in proto
// binary wire format that supports changing an optional field to repeated and vice versa.
// If the field is repeated, we store value as singleton slice of that one value.
v, err := unmarshalJsFieldElement(fd, r, mf, opts)
if err != nil {
return nil, err
}
if v == nil {
return nil, nil
}
if fd.IsRepeated() {
return []interface{}{v}, nil
} else {
return v, nil
}
}
}
func unmarshalJsFieldElement(fd *desc.FieldDescriptor, r *jsReader, mf *MessageFactory, opts *jsonpb.Unmarshaler) (interface{}, error) {
t, err := r.peek()
if err != nil {
return nil, err
}
switch fd.GetType() {
case descriptor.FieldDescriptorProto_TYPE_MESSAGE,
descriptor.FieldDescriptorProto_TYPE_GROUP:
m := mf.NewMessage(fd.GetMessageType())
if dm, ok := m.(*Message); ok {
if err := dm.unmarshalJson(r, opts); err != nil {
return nil, err
}
} else {
var msg json.RawMessage
if err := json.NewDecoder(r.unread()).Decode(&msg); err != nil {
return nil, err
}
if err := r.skip(); err != nil {
return nil, err
}
if err := opts.Unmarshal(bytes.NewReader([]byte(msg)), m); err != nil {
return nil, err
}
}
return m, nil
case descriptor.FieldDescriptorProto_TYPE_ENUM:
if e, err := r.nextNumber(); err != nil {
return nil, err
} else {
// value could be string or number
if i, err := e.Int64(); err != nil {
// number cannot be parsed, so see if it's an enum value name
vd := fd.GetEnumType().FindValueByName(string(e))
if vd != nil {
return vd.GetNumber(), nil
} else {
return nil, fmt.Errorf("enum %q does not have value named %q", fd.GetEnumType().GetFullyQualifiedName(), e)
}
} else if i > math.MaxInt32 || i < math.MinInt32 {
return nil, NumericOverflowError
} else {
return int32(i), err
}
}
case descriptor.FieldDescriptorProto_TYPE_INT32,
descriptor.FieldDescriptorProto_TYPE_SINT32,
descriptor.FieldDescriptorProto_TYPE_SFIXED32:
if i, err := r.nextInt(); err != nil {
return nil, err
} else if i > math.MaxInt32 || i < math.MinInt32 {
return nil, NumericOverflowError
} else {
return int32(i), err
}
case descriptor.FieldDescriptorProto_TYPE_INT64,
descriptor.FieldDescriptorProto_TYPE_SINT64,
descriptor.FieldDescriptorProto_TYPE_SFIXED64:
return r.nextInt()
case descriptor.FieldDescriptorProto_TYPE_UINT32,
descriptor.FieldDescriptorProto_TYPE_FIXED32:
if i, err := r.nextUint(); err != nil {
return nil, err
} else if i > math.MaxUint32 {
return nil, NumericOverflowError
} else {
return uint32(i), err
}
case descriptor.FieldDescriptorProto_TYPE_UINT64,
descriptor.FieldDescriptorProto_TYPE_FIXED64:
return r.nextUint()
case descriptor.FieldDescriptorProto_TYPE_BOOL:
if str, ok := t.(string); ok {
if str == "true" {
r.poll() // consume token
return true, err
} else if str == "false" {
r.poll() // consume token
return false, err
}
}
return r.nextBool()
case descriptor.FieldDescriptorProto_TYPE_FLOAT:
if f, err := r.nextFloat(); err != nil {
return nil, err
} else {
return float32(f), nil
}
case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
return r.nextFloat()
case descriptor.FieldDescriptorProto_TYPE_BYTES:
return r.nextBytes()
case descriptor.FieldDescriptorProto_TYPE_STRING:
return r.nextString()
default:
return nil, fmt.Errorf("unknown field type: %v", fd.GetType())
}
}
type jsReader struct {
reader *bytes.Reader
dec *json.Decoder
current json.Token
peeked bool
}
func newJsReader(b []byte) *jsReader {
reader := bytes.NewReader(b)
dec := json.NewDecoder(reader)
dec.UseNumber()
return &jsReader{reader: reader, dec: dec}
}
func (r *jsReader) unread() io.Reader {
bufs := make([]io.Reader, 3)
var peeked []byte
if r.peeked {
if _, ok := r.current.(json.Delim); ok {
peeked = []byte(fmt.Sprintf("%v", r.current))
} else {
peeked, _ = json.Marshal(r.current)
}
}
readerCopy := *r.reader
decCopy := *r.dec
bufs[0] = bytes.NewReader(peeked)
bufs[1] = decCopy.Buffered()
bufs[2] = &readerCopy
return &concatReader{bufs: bufs}
}
func (r *jsReader) hasNext() bool {
return r.dec.More()
}
func (r *jsReader) peek() (json.Token, error) {
if r.peeked {
return r.current, nil
}
t, err := r.dec.Token()
if err != nil {
return nil, err
}
r.peeked = true
r.current = t
return t, nil
}
func (r *jsReader) poll() (json.Token, error) {
if r.peeked {
ret := r.current
r.current = nil
r.peeked = false
return ret, nil
}
return r.dec.Token()
}
func (r *jsReader) beginObject() error {
_, err := r.expect(func(t json.Token) bool { return t == json.Delim('{') }, nil, "start of JSON object: '{'")
return err
}
func (r *jsReader) endObject() error {
_, err := r.expect(func(t json.Token) bool { return t == json.Delim('}') }, nil, "end of JSON object: '}'")
return err
}
func (r *jsReader) beginArray() error {
_, err := r.expect(func(t json.Token) bool { return t == json.Delim('[') }, nil, "start of array: '['")
return err
}
func (r *jsReader) endArray() error {
_, err := r.expect(func(t json.Token) bool { return t == json.Delim(']') }, nil, "end of array: ']'")
return err
}
func (r *jsReader) nextObjectKey() (string, error) {
return r.nextString()
}
func (r *jsReader) nextString() (string, error) {
t, err := r.expect(func(t json.Token) bool { _, ok := t.(string); return ok }, "", "string")
if err != nil {
return "", err
}
return t.(string), nil
}
func (r *jsReader) nextBytes() ([]byte, error) {
str, err := r.nextString()
if err != nil {
return nil, err
}
return base64.StdEncoding.DecodeString(str)
}
func (r *jsReader) nextBool() (bool, error) {
t, err := r.expect(func(t json.Token) bool { _, ok := t.(bool); return ok }, false, "boolean")
if err != nil {
return false, err
}
return t.(bool), nil
}
func (r *jsReader) nextInt() (int64, error) {
n, err := r.nextNumber()
if err != nil {
return 0, err
}
return n.Int64()
}
func (r *jsReader) nextUint() (uint64, error) {
n, err := r.nextNumber()
if err != nil {
return 0, err
}
return strconv.ParseUint(string(n), 10, 64)
}
func (r *jsReader) nextFloat() (float64, error) {
n, err := r.nextNumber()
if err != nil {
return 0, err
}
return n.Float64()
}
func (r *jsReader) nextNumber() (json.Number, error) {
t, err := r.expect(func(t json.Token) bool { return reflect.TypeOf(t).Kind() == reflect.String }, "0", "number")
if err != nil {
return "", err
}
switch t := t.(type) {
case json.Number:
return t, nil
case string:
return json.Number(t), nil
}
return "", fmt.Errorf("expecting a number but got %v", t)
}
func (r *jsReader) skip() error {
t, err := r.poll()
if err != nil {
return err
}
if t == json.Delim('[') {
if err := r.skipArray(); err != nil {
return err
}
} else if t == json.Delim('{') {
if err := r.skipObject(); err != nil {
return err
}
}
return nil
}
func (r *jsReader) skipArray() error {
for r.hasNext() {
if err := r.skip(); err != nil {
return err
}
}
if err := r.endArray(); err != nil {
return err
}
return nil
}
func (r *jsReader) skipObject() error {
for r.hasNext() {
// skip object key
if err := r.skip(); err != nil {
return err
}
// and value
if err := r.skip(); err != nil {
return err
}
}
if err := r.endObject(); err != nil {
return err
}
return nil
}
func (r *jsReader) expect(predicate func(json.Token) bool, ifNil interface{}, expected string) (interface{}, error) {
t, err := r.poll()
if err != nil {
return nil, err
}
if t == nil && ifNil != nil {
return ifNil, nil
}
if !predicate(t) {
return t, fmt.Errorf("bad input: expecting %s ; instead got %v", expected, t)
}
return t, nil
}
type concatReader struct {
bufs []io.Reader
curr int
}
func (r *concatReader) Read(p []byte) (n int, err error) {
for {
if r.curr >= len(r.bufs) {
err = io.EOF
return
}
var c int
c, err = r.bufs[r.curr].Read(p)
n += c
if err != io.EOF {
return
}
r.curr++
p = p[c:]
}
}
// AnyResolver returns a jsonpb.AnyResolver that uses the given file descriptors
// to resolve message names. It uses the given factory, which may be nil, to
// instantiate messages. The messages that it returns when resolving a type name
// may often be dynamic messages.
func AnyResolver(mf *MessageFactory, files ...*desc.FileDescriptor) jsonpb.AnyResolver {
return &anyResolver{mf: mf, files: files}
}
type anyResolver struct {
mf *MessageFactory
files []*desc.FileDescriptor
ignored map[*desc.FileDescriptor]struct{}
other jsonpb.AnyResolver
}
func wrapResolver(r jsonpb.AnyResolver, mf *MessageFactory, f *desc.FileDescriptor) (jsonpb.AnyResolver, bool) {
if r, ok := r.(*anyResolver); ok {
if _, ok := r.ignored[f]; ok {
// if the current resolver is ignoring this file, it's because another
// (upstream) resolver is already handling it, so nothing to do
return r, false
}
for _, file := range r.files {
if file == f {
// no need to wrap!
return r, false
}
}
// ignore files that will be checked by the resolver we're wrapping
// (we'll just delegate and let it search those files)
ignored := map[*desc.FileDescriptor]struct{}{}
for i := range r.ignored {
ignored[i] = struct{}{}
}
ignore(r.files, ignored)
return &anyResolver{mf: mf, files: []*desc.FileDescriptor{f}, ignored: ignored, other: r}, true
}
return &anyResolver{mf: mf, files: []*desc.FileDescriptor{f}, other: r}, true
}
func ignore(files []*desc.FileDescriptor, ignored map[*desc.FileDescriptor]struct{}) {
for _, f := range files {
if _, ok := ignored[f]; ok {
continue
}
ignored[f] = struct{}{}
ignore(f.GetDependencies(), ignored)
}
}
func (r *anyResolver) Resolve(typeUrl string) (proto.Message, error) {
mname := typeUrl
if slash := strings.LastIndex(mname, "/"); slash >= 0 {
mname = mname[slash+1:]
}
// see if the user-specified resolver is able to do the job
if r.other != nil {
msg, err := r.other.Resolve(typeUrl)
if err == nil {
return msg, nil
}
}
// try to find the message in our known set of files
checked := map[*desc.FileDescriptor]struct{}{}
for _, f := range r.files {
md := r.findMessage(f, mname, checked)
if md != nil {
return r.mf.NewMessage(md), nil
}
}
// failing that, see if the message factory knows about this type
var ktr *KnownTypeRegistry
if r.mf != nil {
ktr = r.mf.ktr
} else {
ktr = (*KnownTypeRegistry)(nil)
}
m := ktr.CreateIfKnown(mname)
if m != nil {
return m, nil
}
// no other resolver to fallback to? mimic default behavior
mt := proto.MessageType(mname)
if mt == nil {
return nil, fmt.Errorf("unknown message type %q", mname)
}
return reflect.New(mt.Elem()).Interface().(proto.Message), nil
}
func (r *anyResolver) findMessage(fd *desc.FileDescriptor, msgName string, checked map[*desc.FileDescriptor]struct{}) *desc.MessageDescriptor {
// if this is an ignored descriptor, skip
if _, ok := r.ignored[fd]; ok {
return nil
}
// bail if we've already checked this file
if _, ok := checked[fd]; ok {
return nil
}
checked[fd] = struct{}{}
// see if this file has the message
md := fd.FindMessage(msgName)
if md != nil {
return md
}
// if not, recursively search the file's imports
for _, dep := range fd.GetDependencies() {
md = r.findMessage(dep, msgName, checked)
if md != nil {
return md
}
}
return nil
}
var _ jsonpb.AnyResolver = (*anyResolver)(nil)