marshal_jsonpb.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. package runtime
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "reflect"
  8. "github.com/golang/protobuf/jsonpb"
  9. "github.com/golang/protobuf/proto"
  10. )
  11. // JSONPb is a Marshaler which marshals/unmarshals into/from JSON
  12. // with the "github.com/golang/protobuf/jsonpb".
  13. // It supports fully functionality of protobuf unlike JSONBuiltin.
  14. type JSONPb jsonpb.Marshaler
  15. // ContentType always returns "application/json".
  16. func (*JSONPb) ContentType() string {
  17. return "application/json"
  18. }
  19. // Marshal marshals "v" into JSON
  20. // Currently it can marshal only proto.Message.
  21. // TODO(yugui) Support fields of primitive types in a message.
  22. func (j *JSONPb) Marshal(v interface{}) ([]byte, error) {
  23. if _, ok := v.(proto.Message); !ok {
  24. return j.marshalNonProtoField(v)
  25. }
  26. var buf bytes.Buffer
  27. if err := j.marshalTo(&buf, v); err != nil {
  28. return nil, err
  29. }
  30. return buf.Bytes(), nil
  31. }
  32. func (j *JSONPb) marshalTo(w io.Writer, v interface{}) error {
  33. p, ok := v.(proto.Message)
  34. if !ok {
  35. buf, err := j.marshalNonProtoField(v)
  36. if err != nil {
  37. return err
  38. }
  39. _, err = w.Write(buf)
  40. return err
  41. }
  42. return (*jsonpb.Marshaler)(j).Marshal(w, p)
  43. }
  44. // marshalNonProto marshals a non-message field of a protobuf message.
  45. // This function does not correctly marshals arbitary data structure into JSON,
  46. // but it is only capable of marshaling non-message field values of protobuf,
  47. // i.e. primitive types, enums; pointers to primitives or enums; maps from
  48. // integer/string types to primitives/enums/pointers to messages.
  49. func (j *JSONPb) marshalNonProtoField(v interface{}) ([]byte, error) {
  50. rv := reflect.ValueOf(v)
  51. for rv.Kind() == reflect.Ptr {
  52. if rv.IsNil() {
  53. return []byte("null"), nil
  54. }
  55. rv = rv.Elem()
  56. }
  57. if rv.Kind() == reflect.Map {
  58. m := make(map[string]*json.RawMessage)
  59. for _, k := range rv.MapKeys() {
  60. buf, err := j.Marshal(rv.MapIndex(k).Interface())
  61. if err != nil {
  62. return nil, err
  63. }
  64. m[fmt.Sprintf("%v", k.Interface())] = (*json.RawMessage)(&buf)
  65. }
  66. if j.Indent != "" {
  67. return json.MarshalIndent(m, "", j.Indent)
  68. }
  69. return json.Marshal(m)
  70. }
  71. if enum, ok := rv.Interface().(protoEnum); ok && !j.EnumsAsInts {
  72. return json.Marshal(enum.String())
  73. }
  74. return json.Marshal(rv.Interface())
  75. }
  76. // Unmarshal unmarshals JSON "data" into "v"
  77. // Currently it can marshal only proto.Message.
  78. // TODO(yugui) Support fields of primitive types in a message.
  79. func (j *JSONPb) Unmarshal(data []byte, v interface{}) error {
  80. return unmarshalJSONPb(data, v)
  81. }
  82. // NewDecoder returns a Decoder which reads JSON stream from "r".
  83. func (j *JSONPb) NewDecoder(r io.Reader) Decoder {
  84. d := json.NewDecoder(r)
  85. return DecoderFunc(func(v interface{}) error { return decodeJSONPb(d, v) })
  86. }
  87. // NewEncoder returns an Encoder which writes JSON stream into "w".
  88. func (j *JSONPb) NewEncoder(w io.Writer) Encoder {
  89. return EncoderFunc(func(v interface{}) error { return j.marshalTo(w, v) })
  90. }
  91. func unmarshalJSONPb(data []byte, v interface{}) error {
  92. d := json.NewDecoder(bytes.NewReader(data))
  93. return decodeJSONPb(d, v)
  94. }
  95. func decodeJSONPb(d *json.Decoder, v interface{}) error {
  96. p, ok := v.(proto.Message)
  97. if !ok {
  98. return decodeNonProtoField(d, v)
  99. }
  100. unmarshaler := &jsonpb.Unmarshaler{AllowUnknownFields: true}
  101. return unmarshaler.UnmarshalNext(d, p)
  102. }
  103. func decodeNonProtoField(d *json.Decoder, v interface{}) error {
  104. rv := reflect.ValueOf(v)
  105. if rv.Kind() != reflect.Ptr {
  106. return fmt.Errorf("%T is not a pointer", v)
  107. }
  108. for rv.Kind() == reflect.Ptr {
  109. if rv.IsNil() {
  110. rv.Set(reflect.New(rv.Type().Elem()))
  111. }
  112. if rv.Type().ConvertibleTo(typeProtoMessage) {
  113. unmarshaler := &jsonpb.Unmarshaler{AllowUnknownFields: true}
  114. return unmarshaler.UnmarshalNext(d, rv.Interface().(proto.Message))
  115. }
  116. rv = rv.Elem()
  117. }
  118. if rv.Kind() == reflect.Map {
  119. if rv.IsNil() {
  120. rv.Set(reflect.MakeMap(rv.Type()))
  121. }
  122. conv, ok := convFromType[rv.Type().Key().Kind()]
  123. if !ok {
  124. return fmt.Errorf("unsupported type of map field key: %v", rv.Type().Key())
  125. }
  126. m := make(map[string]*json.RawMessage)
  127. if err := d.Decode(&m); err != nil {
  128. return err
  129. }
  130. for k, v := range m {
  131. result := conv.Call([]reflect.Value{reflect.ValueOf(k)})
  132. if err := result[1].Interface(); err != nil {
  133. return err.(error)
  134. }
  135. bk := result[0]
  136. bv := reflect.New(rv.Type().Elem())
  137. if err := unmarshalJSONPb([]byte(*v), bv.Interface()); err != nil {
  138. return err
  139. }
  140. rv.SetMapIndex(bk, bv.Elem())
  141. }
  142. return nil
  143. }
  144. if _, ok := rv.Interface().(protoEnum); ok {
  145. var repr interface{}
  146. if err := d.Decode(&repr); err != nil {
  147. return err
  148. }
  149. switch repr.(type) {
  150. case string:
  151. // TODO(yugui) Should use proto.StructProperties?
  152. return fmt.Errorf("unmarshaling of symbolic enum %q not supported: %T", repr, rv.Interface())
  153. case float64:
  154. rv.Set(reflect.ValueOf(int32(repr.(float64))).Convert(rv.Type()))
  155. return nil
  156. default:
  157. return fmt.Errorf("cannot assign %#v into Go type %T", repr, rv.Interface())
  158. }
  159. }
  160. return d.Decode(v)
  161. }
  162. type protoEnum interface {
  163. fmt.Stringer
  164. EnumDescriptor() ([]byte, []int)
  165. }
  166. var typeProtoMessage = reflect.TypeOf((*proto.Message)(nil)).Elem()