blob: f0de351b212dda5c3d770afc66029feee543e7f0 [file] [log] [blame]
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -07001package runtime
2
3import (
4 "bytes"
5 "encoding/json"
6 "fmt"
7 "io"
8 "reflect"
9
10 "github.com/golang/protobuf/jsonpb"
11 "github.com/golang/protobuf/proto"
12)
13
14// JSONPb is a Marshaler which marshals/unmarshals into/from JSON
15// with the "github.com/golang/protobuf/jsonpb".
16// It supports fully functionality of protobuf unlike JSONBuiltin.
17//
18// The NewDecoder method returns a DecoderWrapper, so the underlying
19// *json.Decoder methods can be used.
20type JSONPb jsonpb.Marshaler
21
22// ContentType always returns "application/json".
23func (*JSONPb) ContentType() string {
24 return "application/json"
25}
26
27// Marshal marshals "v" into JSON.
28func (j *JSONPb) Marshal(v interface{}) ([]byte, error) {
29 if _, ok := v.(proto.Message); !ok {
30 return j.marshalNonProtoField(v)
31 }
32
33 var buf bytes.Buffer
34 if err := j.marshalTo(&buf, v); err != nil {
35 return nil, err
36 }
37 return buf.Bytes(), nil
38}
39
40func (j *JSONPb) marshalTo(w io.Writer, v interface{}) error {
41 p, ok := v.(proto.Message)
42 if !ok {
43 buf, err := j.marshalNonProtoField(v)
44 if err != nil {
45 return err
46 }
47 _, err = w.Write(buf)
48 return err
49 }
50 return (*jsonpb.Marshaler)(j).Marshal(w, p)
51}
52
53var (
54 // protoMessageType is stored to prevent constant lookup of the same type at runtime.
55 protoMessageType = reflect.TypeOf((*proto.Message)(nil)).Elem()
56)
57
58// marshalNonProto marshals a non-message field of a protobuf message.
59// This function does not correctly marshals arbitrary data structure into JSON,
60// but it is only capable of marshaling non-message field values of protobuf,
61// i.e. primitive types, enums; pointers to primitives or enums; maps from
62// integer/string types to primitives/enums/pointers to messages.
63func (j *JSONPb) marshalNonProtoField(v interface{}) ([]byte, error) {
64 if v == nil {
65 return []byte("null"), nil
66 }
67 rv := reflect.ValueOf(v)
68 for rv.Kind() == reflect.Ptr {
69 if rv.IsNil() {
70 return []byte("null"), nil
71 }
72 rv = rv.Elem()
73 }
74
75 if rv.Kind() == reflect.Slice {
76 if rv.IsNil() {
77 if j.EmitDefaults {
78 return []byte("[]"), nil
79 }
80 return []byte("null"), nil
81 }
82
83 if rv.Type().Elem().Implements(protoMessageType) {
84 var buf bytes.Buffer
85 err := buf.WriteByte('[')
86 if err != nil {
87 return nil, err
88 }
89 for i := 0; i < rv.Len(); i++ {
90 if i != 0 {
91 err = buf.WriteByte(',')
92 if err != nil {
93 return nil, err
94 }
95 }
96 if err = (*jsonpb.Marshaler)(j).Marshal(&buf, rv.Index(i).Interface().(proto.Message)); err != nil {
97 return nil, err
98 }
99 }
100 err = buf.WriteByte(']')
101 if err != nil {
102 return nil, err
103 }
104
105 return buf.Bytes(), nil
106 }
107 }
108
109 if rv.Kind() == reflect.Map {
110 m := make(map[string]*json.RawMessage)
111 for _, k := range rv.MapKeys() {
112 buf, err := j.Marshal(rv.MapIndex(k).Interface())
113 if err != nil {
114 return nil, err
115 }
116 m[fmt.Sprintf("%v", k.Interface())] = (*json.RawMessage)(&buf)
117 }
118 if j.Indent != "" {
119 return json.MarshalIndent(m, "", j.Indent)
120 }
121 return json.Marshal(m)
122 }
123 if enum, ok := rv.Interface().(protoEnum); ok && !j.EnumsAsInts {
124 return json.Marshal(enum.String())
125 }
126 return json.Marshal(rv.Interface())
127}
128
129// Unmarshal unmarshals JSON "data" into "v"
130func (j *JSONPb) Unmarshal(data []byte, v interface{}) error {
131 return unmarshalJSONPb(data, v)
132}
133
134// NewDecoder returns a Decoder which reads JSON stream from "r".
135func (j *JSONPb) NewDecoder(r io.Reader) Decoder {
136 d := json.NewDecoder(r)
137 return DecoderWrapper{Decoder: d}
138}
139
140// DecoderWrapper is a wrapper around a *json.Decoder that adds
141// support for protos to the Decode method.
142type DecoderWrapper struct {
143 *json.Decoder
144}
145
146// Decode wraps the embedded decoder's Decode method to support
147// protos using a jsonpb.Unmarshaler.
148func (d DecoderWrapper) Decode(v interface{}) error {
149 return decodeJSONPb(d.Decoder, v)
150}
151
152// NewEncoder returns an Encoder which writes JSON stream into "w".
153func (j *JSONPb) NewEncoder(w io.Writer) Encoder {
154 return EncoderFunc(func(v interface{}) error {
155 if err := j.marshalTo(w, v); err != nil {
156 return err
157 }
158 // mimic json.Encoder by adding a newline (makes output
159 // easier to read when it contains multiple encoded items)
160 _, err := w.Write(j.Delimiter())
161 return err
162 })
163}
164
165func unmarshalJSONPb(data []byte, v interface{}) error {
166 d := json.NewDecoder(bytes.NewReader(data))
167 return decodeJSONPb(d, v)
168}
169
170func decodeJSONPb(d *json.Decoder, v interface{}) error {
171 p, ok := v.(proto.Message)
172 if !ok {
173 return decodeNonProtoField(d, v)
174 }
175 unmarshaler := &jsonpb.Unmarshaler{AllowUnknownFields: allowUnknownFields}
176 return unmarshaler.UnmarshalNext(d, p)
177}
178
179func decodeNonProtoField(d *json.Decoder, v interface{}) error {
180 rv := reflect.ValueOf(v)
181 if rv.Kind() != reflect.Ptr {
182 return fmt.Errorf("%T is not a pointer", v)
183 }
184 for rv.Kind() == reflect.Ptr {
185 if rv.IsNil() {
186 rv.Set(reflect.New(rv.Type().Elem()))
187 }
188 if rv.Type().ConvertibleTo(typeProtoMessage) {
189 unmarshaler := &jsonpb.Unmarshaler{AllowUnknownFields: allowUnknownFields}
190 return unmarshaler.UnmarshalNext(d, rv.Interface().(proto.Message))
191 }
192 rv = rv.Elem()
193 }
194 if rv.Kind() == reflect.Map {
195 if rv.IsNil() {
196 rv.Set(reflect.MakeMap(rv.Type()))
197 }
198 conv, ok := convFromType[rv.Type().Key().Kind()]
199 if !ok {
200 return fmt.Errorf("unsupported type of map field key: %v", rv.Type().Key())
201 }
202
203 m := make(map[string]*json.RawMessage)
204 if err := d.Decode(&m); err != nil {
205 return err
206 }
207 for k, v := range m {
208 result := conv.Call([]reflect.Value{reflect.ValueOf(k)})
209 if err := result[1].Interface(); err != nil {
210 return err.(error)
211 }
212 bk := result[0]
213 bv := reflect.New(rv.Type().Elem())
214 if err := unmarshalJSONPb([]byte(*v), bv.Interface()); err != nil {
215 return err
216 }
217 rv.SetMapIndex(bk, bv.Elem())
218 }
219 return nil
220 }
221 if _, ok := rv.Interface().(protoEnum); ok {
222 var repr interface{}
223 if err := d.Decode(&repr); err != nil {
224 return err
225 }
226 switch repr.(type) {
227 case string:
228 // TODO(yugui) Should use proto.StructProperties?
229 return fmt.Errorf("unmarshaling of symbolic enum %q not supported: %T", repr, rv.Interface())
230 case float64:
231 rv.Set(reflect.ValueOf(int32(repr.(float64))).Convert(rv.Type()))
232 return nil
233 default:
234 return fmt.Errorf("cannot assign %#v into Go type %T", repr, rv.Interface())
235 }
236 }
237 return d.Decode(v)
238}
239
240type protoEnum interface {
241 fmt.Stringer
242 EnumDescriptor() ([]byte, []int)
243}
244
245var typeProtoMessage = reflect.TypeOf((*proto.Message)(nil)).Elem()
246
247// Delimiter for newline encoded JSON streams.
248func (j *JSONPb) Delimiter() []byte {
249 return []byte("\n")
250}
251
252// allowUnknownFields helps not to return an error when the destination
253// is a struct and the input contains object keys which do not match any
254// non-ignored, exported fields in the destination.
255var allowUnknownFields = true
256
257// DisallowUnknownFields enables option in decoder (unmarshaller) to
258// return an error when it finds an unknown field. This function must be
259// called before using the JSON marshaller.
260func DisallowUnknownFields() {
261 allowUnknownFields = false
262}