123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713 |
- // Go support for Protocol Buffers - Google's data interchange format
- //
- // Copyright 2015 The Go Authors. All rights reserved.
- // https://github.com/golang/protobuf
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are
- // met:
- //
- // * Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- // * Redistributions in binary form must reproduce the above
- // copyright notice, this list of conditions and the following disclaimer
- // in the documentation and/or other materials provided with the
- // distribution.
- // * Neither the name of Google Inc. nor the names of its
- // contributors may be used to endorse or promote products derived from
- // this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- /*
- Package jsonpb provides marshaling and unmarshaling between protocol buffers and JSON.
- It follows the specification at https://developers.google.com/protocol-buffers/docs/proto3#json.
- This package produces a different output than the standard "encoding/json" package,
- which does not operate correctly on protocol buffers.
- */
- package jsonpb
- import (
- "bytes"
- "encoding/json"
- "fmt"
- "io"
- "reflect"
- "sort"
- "strconv"
- "strings"
- "github.com/gogo/protobuf/proto"
- )
- // Marshaler is a configurable object for converting between
- // protocol buffer objects and a JSON representation for them.
- type Marshaler struct {
- // Whether to render enum values as integers, as opposed to string values.
- EnumsAsInts bool
- // Whether to render fields with zero values.
- EmitDefaults bool
- // A string to indent each level by. The presence of this field will
- // also cause a space to appear between the field separator and
- // value, and for newlines to be appear between fields and array
- // elements.
- Indent string
- // Whether to use the original (.proto) name for fields.
- OrigName bool
- }
- // Marshal marshals a protocol buffer into JSON.
- func (m *Marshaler) Marshal(out io.Writer, pb proto.Message) error {
- writer := &errWriter{writer: out}
- return m.marshalObject(writer, pb, "")
- }
- // MarshalToString converts a protocol buffer object to JSON string.
- func (m *Marshaler) MarshalToString(pb proto.Message) (string, error) {
- var buf bytes.Buffer
- if err := m.Marshal(&buf, pb); err != nil {
- return "", err
- }
- return buf.String(), nil
- }
- type int32Slice []int32
- // For sorting extensions ids to ensure stable output.
- func (s int32Slice) Len() int { return len(s) }
- func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] }
- func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
- // marshalObject writes a struct to the Writer.
- func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent string) error {
- out.write("{")
- if m.Indent != "" {
- out.write("\n")
- }
- s := reflect.ValueOf(v).Elem()
- firstField := true
- for i := 0; i < s.NumField(); i++ {
- value := s.Field(i)
- valueField := s.Type().Field(i)
- if strings.HasPrefix(valueField.Name, "XXX_") {
- continue
- }
- // IsNil will panic on most value kinds.
- switch value.Kind() {
- case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
- if value.IsNil() {
- continue
- }
- }
- if !m.EmitDefaults {
- switch value.Kind() {
- case reflect.Bool:
- if !value.Bool() {
- continue
- }
- case reflect.Int32, reflect.Int64:
- if value.Int() == 0 {
- continue
- }
- case reflect.Uint32, reflect.Uint64:
- if value.Uint() == 0 {
- continue
- }
- case reflect.Float32, reflect.Float64:
- if value.Float() == 0 {
- continue
- }
- case reflect.String:
- if value.Len() == 0 {
- continue
- }
- }
- }
- // Oneof fields need special handling.
- if valueField.Tag.Get("protobuf_oneof") != "" {
- // value is an interface containing &T{real_value}.
- sv := value.Elem().Elem() // interface -> *T -> T
- value = sv.Field(0)
- valueField = sv.Type().Field(0)
- }
- prop := jsonProperties(valueField, m.OrigName)
- if !firstField {
- m.writeSep(out)
- }
- // If the map value is a cast type, it may not implement proto.Message, therefore
- // allow the struct tag to declare the underlying message type. Instead of changing
- // the signatures of the child types (and because prop.mvalue is not public), use
- // CustomType as a passer.
- if value.Kind() == reflect.Map {
- if tag := valueField.Tag.Get("protobuf"); tag != "" {
- for _, v := range strings.Split(tag, ",") {
- if !strings.HasPrefix(v, "castvaluetype=") {
- continue
- }
- v = strings.TrimPrefix(v, "castvaluetype=")
- prop.CustomType = v
- break
- }
- }
- }
- if err := m.marshalField(out, prop, value, indent); err != nil {
- return err
- }
- firstField = false
- }
- // Handle proto2 extensions.
- if ep, ok := v.(proto.Message); ok {
- extensions := proto.RegisteredExtensions(v)
- // Sort extensions for stable output.
- ids := make([]int32, 0, len(extensions))
- for id, desc := range extensions {
- if !proto.HasExtension(ep, desc) {
- continue
- }
- ids = append(ids, id)
- }
- sort.Sort(int32Slice(ids))
- for _, id := range ids {
- desc := extensions[id]
- if desc == nil {
- // unknown extension
- continue
- }
- ext, extErr := proto.GetExtension(ep, desc)
- if extErr != nil {
- return extErr
- }
- value := reflect.ValueOf(ext)
- var prop proto.Properties
- prop.Parse(desc.Tag)
- prop.JSONName = fmt.Sprintf("[%s]", desc.Name)
- if !firstField {
- m.writeSep(out)
- }
- if err := m.marshalField(out, &prop, value, indent); err != nil {
- return err
- }
- firstField = false
- }
- }
- if m.Indent != "" {
- out.write("\n")
- out.write(indent)
- }
- out.write("}")
- return out.err
- }
- func (m *Marshaler) writeSep(out *errWriter) {
- if m.Indent != "" {
- out.write(",\n")
- } else {
- out.write(",")
- }
- }
- // marshalField writes field description and value to the Writer.
- func (m *Marshaler) marshalField(out *errWriter, prop *proto.Properties, v reflect.Value, indent string) error {
- if m.Indent != "" {
- out.write(indent)
- out.write(m.Indent)
- }
- out.write(`"`)
- out.write(prop.JSONName)
- out.write(`":`)
- if m.Indent != "" {
- out.write(" ")
- }
- if err := m.marshalValue(out, prop, v, indent); err != nil {
- return err
- }
- return nil
- }
- // marshalValue writes the value to the Writer.
- func (m *Marshaler) marshalValue(out *errWriter, prop *proto.Properties, v reflect.Value, indent string) error {
- v = reflect.Indirect(v)
- // Handle repeated elements.
- if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 {
- out.write("[")
- comma := ""
- for i := 0; i < v.Len(); i++ {
- sliceVal := v.Index(i)
- out.write(comma)
- if m.Indent != "" {
- out.write("\n")
- out.write(indent)
- out.write(m.Indent)
- out.write(m.Indent)
- }
- if err := m.marshalValue(out, prop, sliceVal, indent+m.Indent); err != nil {
- return err
- }
- comma = ","
- }
- if m.Indent != "" {
- out.write("\n")
- out.write(indent)
- out.write(m.Indent)
- }
- out.write("]")
- return out.err
- }
- // Handle enumerations.
- if !m.EnumsAsInts && prop.Enum != "" {
- // Unknown enum values will are stringified by the proto library as their
- // value. Such values should _not_ be quoted or they will be interpreted
- // as an enum string instead of their value.
- enumStr := v.Interface().(fmt.Stringer).String()
- var valStr string
- if v.Kind() == reflect.Ptr {
- valStr = strconv.Itoa(int(v.Elem().Int()))
- } else {
- valStr = strconv.Itoa(int(v.Int()))
- }
- if m, ok := v.Interface().(interface {
- MarshalJSON() ([]byte, error)
- }); ok {
- data, err := m.MarshalJSON()
- if err != nil {
- return err
- }
- enumStr = string(data)
- enumStr, err = strconv.Unquote(enumStr)
- if err != nil {
- return err
- }
- }
- isKnownEnum := enumStr != valStr
- if isKnownEnum {
- out.write(`"`)
- }
- out.write(enumStr)
- if isKnownEnum {
- out.write(`"`)
- }
- return out.err
- }
- // Handle nested messages.
- if v.Kind() == reflect.Struct {
- i := v
- if v.CanAddr() {
- i = v.Addr()
- } else {
- i = reflect.New(v.Type())
- i.Elem().Set(v)
- }
- iface := i.Interface()
- if iface == nil {
- out.write(`null`)
- return out.err
- }
- pm, ok := iface.(proto.Message)
- if !ok {
- if prop.CustomType == "" {
- return fmt.Errorf("%v does not implement proto.Message", v.Type())
- }
- t := proto.MessageType(prop.CustomType)
- if t == nil || !i.Type().ConvertibleTo(t) {
- return fmt.Errorf("%v declared custom type %s but it is not convertible to %v", v.Type(), prop.CustomType, t)
- }
- pm = i.Convert(t).Interface().(proto.Message)
- }
- return m.marshalObject(out, pm, indent+m.Indent)
- }
- // Handle maps.
- // Since Go randomizes map iteration, we sort keys for stable output.
- if v.Kind() == reflect.Map {
- out.write(`{`)
- keys := v.MapKeys()
- sort.Sort(mapKeys(keys))
- for i, k := range keys {
- if i > 0 {
- out.write(`,`)
- }
- if m.Indent != "" {
- out.write("\n")
- out.write(indent)
- out.write(m.Indent)
- out.write(m.Indent)
- }
- b, err := json.Marshal(k.Interface())
- if err != nil {
- return err
- }
- s := string(b)
- // If the JSON is not a string value, encode it again to make it one.
- if !strings.HasPrefix(s, `"`) {
- b, err := json.Marshal(s)
- if err != nil {
- return err
- }
- s = string(b)
- }
- out.write(s)
- out.write(`:`)
- if m.Indent != "" {
- out.write(` `)
- }
- if err := m.marshalValue(out, prop, v.MapIndex(k), indent+m.Indent); err != nil {
- return err
- }
- }
- if m.Indent != "" {
- out.write("\n")
- out.write(indent)
- out.write(m.Indent)
- }
- out.write(`}`)
- return out.err
- }
- // Default handling defers to the encoding/json library.
- b, err := json.Marshal(v.Interface())
- if err != nil {
- return err
- }
- needToQuote := string(b[0]) != `"` && (v.Kind() == reflect.Int64 || v.Kind() == reflect.Uint64)
- if needToQuote {
- out.write(`"`)
- }
- out.write(string(b))
- if needToQuote {
- out.write(`"`)
- }
- return out.err
- }
- // Unmarshaler is a configurable object for converting from a JSON
- // representation to a protocol buffer object.
- type Unmarshaler struct {
- // Whether to allow messages to contain unknown fields, as opposed to
- // failing to unmarshal.
- AllowUnknownFields bool
- }
- // UnmarshalNext unmarshals the next protocol buffer from a JSON object stream.
- // This function is lenient and will decode any options permutations of the
- // related Marshaler.
- func (u *Unmarshaler) UnmarshalNext(dec *json.Decoder, pb proto.Message) error {
- inputValue := json.RawMessage{}
- if err := dec.Decode(&inputValue); err != nil {
- return err
- }
- return u.unmarshalValue(reflect.ValueOf(pb).Elem(), inputValue, nil)
- }
- // Unmarshal unmarshals a JSON object stream into a protocol
- // buffer. This function is lenient and will decode any options
- // permutations of the related Marshaler.
- func (u *Unmarshaler) Unmarshal(r io.Reader, pb proto.Message) error {
- dec := json.NewDecoder(r)
- return u.UnmarshalNext(dec, pb)
- }
- // UnmarshalNext unmarshals the next protocol buffer from a JSON object stream.
- // This function is lenient and will decode any options permutations of the
- // related Marshaler.
- func UnmarshalNext(dec *json.Decoder, pb proto.Message) error {
- return new(Unmarshaler).UnmarshalNext(dec, pb)
- }
- // Unmarshal unmarshals a JSON object stream into a protocol
- // buffer. This function is lenient and will decode any options
- // permutations of the related Marshaler.
- func Unmarshal(r io.Reader, pb proto.Message) error {
- return new(Unmarshaler).Unmarshal(r, pb)
- }
- // UnmarshalString will populate the fields of a protocol buffer based
- // on a JSON string. This function is lenient and will decode any options
- // permutations of the related Marshaler.
- func UnmarshalString(str string, pb proto.Message) error {
- return new(Unmarshaler).Unmarshal(strings.NewReader(str), pb)
- }
- // unmarshalValue converts/copies a value into the target.
- // prop may be nil.
- func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMessage, prop *proto.Properties) error {
- targetType := target.Type()
- // Allocate memory for pointer fields.
- if targetType.Kind() == reflect.Ptr {
- target.Set(reflect.New(targetType.Elem()))
- return u.unmarshalValue(target.Elem(), inputValue, prop)
- }
- // Handle enums, which have an underlying type of int32,
- // and may appear as strings.
- // The case of an enum appearing as a number is handled
- // at the bottom of this function.
- if inputValue[0] == '"' && prop != nil && prop.Enum != "" {
- vmap := proto.EnumValueMap(prop.Enum)
- // Don't need to do unquoting; valid enum names
- // are from a limited character set.
- s := inputValue[1 : len(inputValue)-1]
- n, ok := vmap[string(s)]
- if !ok {
- return fmt.Errorf("unknown value %q for enum %s", s, prop.Enum)
- }
- if target.Kind() == reflect.Ptr { // proto2
- target.Set(reflect.New(targetType.Elem()))
- target = target.Elem()
- }
- target.SetInt(int64(n))
- return nil
- }
- // Handle nested messages.
- if targetType.Kind() == reflect.Struct {
- var jsonFields map[string]json.RawMessage
- if err := json.Unmarshal(inputValue, &jsonFields); err != nil {
- return err
- }
- consumeField := func(prop *proto.Properties) (json.RawMessage, bool) {
- // Be liberal in what names we accept; both orig_name and camelName are okay.
- fieldNames := acceptedJSONFieldNames(prop)
- vOrig, okOrig := jsonFields[fieldNames.orig]
- vCamel, okCamel := jsonFields[fieldNames.camel]
- if !okOrig && !okCamel {
- return nil, false
- }
- // If, for some reason, both are present in the data, favour the camelName.
- var raw json.RawMessage
- if okOrig {
- raw = vOrig
- delete(jsonFields, fieldNames.orig)
- }
- if okCamel {
- raw = vCamel
- delete(jsonFields, fieldNames.camel)
- }
- return raw, true
- }
- sprops := proto.GetProperties(targetType)
- for i := 0; i < target.NumField(); i++ {
- ft := target.Type().Field(i)
- if strings.HasPrefix(ft.Name, "XXX_") {
- continue
- }
- valueForField, ok := consumeField(sprops.Prop[i])
- if !ok {
- continue
- }
- if err := u.unmarshalValue(target.Field(i), valueForField, sprops.Prop[i]); err != nil {
- return err
- }
- }
- // Check for any oneof fields.
- if len(jsonFields) > 0 {
- for _, oop := range sprops.OneofTypes {
- raw, ok := consumeField(oop.Prop)
- if !ok {
- continue
- }
- nv := reflect.New(oop.Type.Elem())
- target.Field(oop.Field).Set(nv)
- if err := u.unmarshalValue(nv.Elem().Field(0), raw, oop.Prop); err != nil {
- return err
- }
- }
- }
- if !u.AllowUnknownFields && len(jsonFields) > 0 {
- // Pick any field to be the scapegoat.
- var f string
- for fname := range jsonFields {
- f = fname
- break
- }
- return fmt.Errorf("unknown field %q in %v", f, targetType)
- }
- return nil
- }
- // Handle arrays
- if targetType.Kind() == reflect.Slice {
- if targetType.Elem().Kind() == reflect.Uint8 {
- outRef := reflect.New(targetType)
- outVal := outRef.Interface()
- //CustomType with underlying type []byte
- if _, ok := outVal.(interface {
- UnmarshalJSON([]byte) error
- }); ok {
- if err := json.Unmarshal(inputValue, outVal); err != nil {
- return err
- }
- target.Set(outRef.Elem())
- return nil
- }
- // Special case for encoded bytes. Pre-go1.5 doesn't support unmarshalling
- // strings into aliased []byte types.
- // https://github.com/golang/go/commit/4302fd0409da5e4f1d71471a6770dacdc3301197
- // https://github.com/golang/go/commit/c60707b14d6be26bf4213114d13070bff00d0b0a
- var out []byte
- if err := json.Unmarshal(inputValue, &out); err != nil {
- return err
- }
- target.SetBytes(out)
- return nil
- }
- var slc []json.RawMessage
- if err := json.Unmarshal(inputValue, &slc); err != nil {
- return err
- }
- len := len(slc)
- target.Set(reflect.MakeSlice(targetType, len, len))
- for i := 0; i < len; i++ {
- if err := u.unmarshalValue(target.Index(i), slc[i], prop); err != nil {
- return err
- }
- }
- return nil
- }
- // Handle maps (whose keys are always strings)
- if targetType.Kind() == reflect.Map {
- var mp map[string]json.RawMessage
- if err := json.Unmarshal(inputValue, &mp); err != nil {
- return err
- }
- target.Set(reflect.MakeMap(targetType))
- var keyprop, valprop *proto.Properties
- if prop != nil {
- // These could still be nil if the protobuf metadata is broken somehow.
- // TODO: This won't work because the fields are unexported.
- // We should probably just reparse them.
- //keyprop, valprop = prop.mkeyprop, prop.mvalprop
- }
- for ks, raw := range mp {
- // Unmarshal map key. The core json library already decoded the key into a
- // string, so we handle that specially. Other types were quoted post-serialization.
- var k reflect.Value
- if targetType.Key().Kind() == reflect.String {
- k = reflect.ValueOf(ks)
- } else {
- k = reflect.New(targetType.Key()).Elem()
- if err := u.unmarshalValue(k, json.RawMessage(ks), keyprop); err != nil {
- return err
- }
- }
- if !k.Type().AssignableTo(targetType.Key()) {
- k = k.Convert(targetType.Key())
- }
- // Unmarshal map value.
- v := reflect.New(targetType.Elem()).Elem()
- if err := u.unmarshalValue(v, raw, valprop); err != nil {
- return err
- }
- target.SetMapIndex(k, v)
- }
- return nil
- }
- // 64-bit integers can be encoded as strings. In this case we drop
- // the quotes and proceed as normal.
- isNum := targetType.Kind() == reflect.Int64 || targetType.Kind() == reflect.Uint64
- if isNum && strings.HasPrefix(string(inputValue), `"`) {
- inputValue = inputValue[1 : len(inputValue)-1]
- }
- // Use the encoding/json for parsing other value types.
- return json.Unmarshal(inputValue, target.Addr().Interface())
- }
- // jsonProperties returns parsed proto.Properties for the field and corrects JSONName attribute.
- func jsonProperties(f reflect.StructField, origName bool) *proto.Properties {
- var prop proto.Properties
- prop.Init(f.Type, f.Name, f.Tag.Get("protobuf"), &f)
- if origName || prop.JSONName == "" {
- prop.JSONName = prop.OrigName
- }
- return &prop
- }
- type fieldNames struct {
- orig, camel string
- }
- func acceptedJSONFieldNames(prop *proto.Properties) fieldNames {
- opts := fieldNames{orig: prop.OrigName, camel: prop.OrigName}
- if prop.JSONName != "" {
- opts.camel = prop.JSONName
- }
- return opts
- }
- // Writer wrapper inspired by https://blog.golang.org/errors-are-values
- type errWriter struct {
- writer io.Writer
- err error
- }
- func (w *errWriter) write(str string) {
- if w.err != nil {
- return
- }
- _, w.err = w.writer.Write([]byte(str))
- }
- // Map fields may have key types of non-float scalars, strings and enums.
- // The easiest way to sort them in some deterministic order is to use fmt.
- // If this turns out to be inefficient we can always consider other options,
- // such as doing a Schwartzian transform.
- //
- // Numeric keys are sorted in numeric order per
- // https://developers.google.com/protocol-buffers/docs/proto#maps.
- type mapKeys []reflect.Value
- func (s mapKeys) Len() int { return len(s) }
- func (s mapKeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
- func (s mapKeys) Less(i, j int) bool {
- if k := s[i].Kind(); k == s[j].Kind() {
- switch k {
- case reflect.Int32, reflect.Int64:
- return s[i].Int() < s[j].Int()
- case reflect.Uint32, reflect.Uint64:
- return s[i].Uint() < s[j].Uint()
- }
- }
- return fmt.Sprint(s[i].Interface()) < fmt.Sprint(s[j].Interface())
- }
|