blob: 2663c92cfb0612c1cfa26ba6e052caded6cceb1a [file] [log] [blame]
Buck Clay67cbcad2015-07-01 11:17:11 +10001// Go support for Protocol Buffers - Google's data interchange format
2//
3// Copyright 2015 The Go Authors. All rights reserved.
4// https://github.com/golang/protobuf
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
9//
10// * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12// * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16// * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32/*
David Symonds21f81362015-08-17 11:59:00 +100033Package jsonpb provides marshaling/unmarshaling functionality between
Buck Clay67cbcad2015-07-01 11:17:11 +100034protocol buffer and JSON objects.
35
36Compared to encoding/json, this library:
37 - encodes int64, uint64 as strings
38 - optionally encodes enums as strings
39*/
40package jsonpb
41
42import (
43 "bytes"
44 "encoding/json"
45 "fmt"
46 "io"
47 "reflect"
48 "sort"
49 "strconv"
50 "strings"
51
52 "github.com/golang/protobuf/proto"
53)
54
55var (
56 byteArrayType = reflect.TypeOf([]byte{})
57)
58
David Symonds21f81362015-08-17 11:59:00 +100059// Marshaler is a configurable object for converting between
Buck Clay67cbcad2015-07-01 11:17:11 +100060// protocol buffer objects and a JSON representation for them
David Symonds21f81362015-08-17 11:59:00 +100061type Marshaler struct {
Buck Clay67cbcad2015-07-01 11:17:11 +100062 // Use string values for enums (as opposed to integer values)
63 EnumsAsString bool
64
65 // A string to indent each level by. The presence of this field will
66 // also cause a space to appear between the field separator and
67 // value, and for newlines to be appear between fields and array
68 // elements.
69 Indent string
70}
71
72// Marshal marshals a protocol buffer into JSON.
David Symonds21f81362015-08-17 11:59:00 +100073func (m *Marshaler) Marshal(out io.Writer, pb proto.Message) error {
Buck Clay67cbcad2015-07-01 11:17:11 +100074 writer := &errWriter{writer: out}
75 return m.marshalObject(writer, pb, "")
76}
77
78// MarshalToString converts a protocol buffer object to JSON string.
David Symonds21f81362015-08-17 11:59:00 +100079func (m *Marshaler) MarshalToString(pb proto.Message) (string, error) {
Buck Clay67cbcad2015-07-01 11:17:11 +100080 var buf bytes.Buffer
81 if err := m.Marshal(&buf, pb); err != nil {
82 return "", err
83 }
84 return buf.String(), nil
85}
86
87// marshalObject writes a struct to the Writer.
David Symonds21f81362015-08-17 11:59:00 +100088func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent string) error {
Buck Clay67cbcad2015-07-01 11:17:11 +100089 out.write("{")
90 if m.Indent != "" {
91 out.write("\n")
92 }
93
94 s := reflect.ValueOf(v).Elem()
95 writeBeforeField := ""
96 for i := 0; i < s.NumField(); i++ {
97 value := s.Field(i)
98 valueField := s.Type().Field(i)
David Symonds31db5692015-08-10 12:45:00 +100099 if strings.HasPrefix(valueField.Name, "XXX_") {
Buck Clay67cbcad2015-07-01 11:17:11 +1000100 continue
David Symonds31db5692015-08-10 12:45:00 +1000101 }
102 fieldName := jsonFieldName(valueField)
103
104 // TODO: proto3 objects should have default values omitted.
105
106 // IsNil will panic on most value kinds.
107 switch value.Kind() {
108 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
109 if value.IsNil() {
Buck Clay67cbcad2015-07-01 11:17:11 +1000110 continue
111 }
112 }
113
David Symonds59b73b32015-08-24 13:22:02 +1000114 // Oneof fields need special handling.
115 if valueField.Tag.Get("protobuf_oneof") != "" {
116 // value is an interface containing &T{real_value}.
117 sv := value.Elem().Elem() // interface -> *T -> T
118 value = sv.Field(0)
119 valueField = sv.Type().Field(0)
120
121 var p proto.Properties
122 p.Parse(sv.Type().Field(0).Tag.Get("protobuf"))
123 fieldName = p.OrigName
124 }
125
Buck Clay67cbcad2015-07-01 11:17:11 +1000126 out.write(writeBeforeField)
127 if m.Indent != "" {
128 out.write(indent)
129 out.write(m.Indent)
130 }
131 out.write(`"`)
132 out.write(fieldName)
133 out.write(`":`)
134 if m.Indent != "" {
135 out.write(" ")
136 }
137
138 if err := m.marshalValue(out, value, valueField, indent); err != nil {
139 return err
140 }
141
142 if m.Indent != "" {
143 writeBeforeField = ",\n"
144 } else {
145 writeBeforeField = ","
146 }
147 }
148
149 if m.Indent != "" {
150 out.write("\n")
151 out.write(indent)
152 }
153 out.write("}")
154 return out.err
155}
156
157// marshalValue writes the value to the Writer.
David Symonds21f81362015-08-17 11:59:00 +1000158func (m *Marshaler) marshalValue(out *errWriter, v reflect.Value,
Buck Clay67cbcad2015-07-01 11:17:11 +1000159 structField reflect.StructField, indent string) error {
160
161 var err error
162 v = reflect.Indirect(v)
163
164 // Handle repeated elements.
165 if v.Type() != byteArrayType && v.Kind() == reflect.Slice {
166 out.write("[")
167 comma := ""
168 for i := 0; i < v.Len(); i++ {
169 sliceVal := v.Index(i)
170 out.write(comma)
171 if m.Indent != "" {
172 out.write("\n")
173 out.write(indent)
174 out.write(m.Indent)
175 out.write(m.Indent)
176 }
177 m.marshalValue(out, sliceVal, structField, indent+m.Indent)
178 comma = ","
179 }
180 if m.Indent != "" {
181 out.write("\n")
182 out.write(indent)
183 out.write(m.Indent)
184 }
185 out.write("]")
186 return out.err
187 }
188
189 // Handle enumerations.
190 protoInfo := structField.Tag.Get("protobuf")
191 if m.EnumsAsString && strings.Contains(protoInfo, ",enum=") {
192 // Unknown enum values will are stringified by the proto library as their
193 // value. Such values should _not_ be quoted or they will be intrepreted
194 // as an enum string instead of their value.
195 enumStr := v.Interface().(fmt.Stringer).String()
196 var valStr string
197 if v.Kind() == reflect.Ptr {
198 valStr = strconv.Itoa(int(v.Elem().Int()))
199 } else {
200 valStr = strconv.Itoa(int(v.Int()))
201 }
202 isKnownEnum := enumStr != valStr
203 if isKnownEnum {
204 out.write(`"`)
205 }
206 out.write(enumStr)
207 if isKnownEnum {
208 out.write(`"`)
209 }
210 return out.err
211 }
212
213 // Handle nested messages.
214 if v.Kind() == reflect.Struct {
215 return m.marshalObject(out, v.Addr().Interface().(proto.Message), indent+m.Indent)
216 }
217
218 // Handle maps.
David Symonds3fe63ce2015-08-07 15:00:00 +1000219 // Since Go randomizes map iteration, we sort keys for stable output.
Buck Clay67cbcad2015-07-01 11:17:11 +1000220 if v.Kind() == reflect.Map {
221 out.write(`{`)
222 keys := v.MapKeys()
223 sort.Sort(mapKeys(keys))
224 for i, k := range keys {
225 if i > 0 {
226 out.write(`,`)
227 }
228 if m.Indent != "" {
229 out.write("\n")
230 out.write(indent)
231 out.write(m.Indent)
232 out.write(m.Indent)
233 }
234
235 b, err := json.Marshal(k.Interface())
236 if err != nil {
237 return err
238 }
239 s := string(b)
240
241 // If the JSON is not a string value, encode it again to make it one.
242 if !strings.HasPrefix(s, `"`) {
243 b, err := json.Marshal(s)
244 if err != nil {
245 return err
246 }
247 s = string(b)
248 }
249
250 out.write(s)
251 out.write(`:`)
252 if m.Indent != "" {
253 out.write(` `)
254 }
255
256 if err := m.marshalValue(out, v.MapIndex(k), structField, indent+m.Indent); err != nil {
257 return err
258 }
259 }
260 if m.Indent != "" {
261 out.write("\n")
262 out.write(indent)
263 out.write(m.Indent)
264 }
265 out.write(`}`)
266 return out.err
267 }
268
269 // Default handling defers to the encoding/json library.
270 b, err := json.Marshal(v.Interface())
271 if err != nil {
272 return err
273 }
274 needToQuote := string(b[0]) != `"` && (v.Kind() == reflect.Int64 || v.Kind() == reflect.Uint64)
275 if needToQuote {
276 out.write(`"`)
277 }
278 out.write(string(b))
279 if needToQuote {
280 out.write(`"`)
281 }
282 return out.err
283}
284
285// Unmarshal unmarshals a JSON object stream into a protocol
286// buffer. This function is lenient and will decode any options
David Symonds21f81362015-08-17 11:59:00 +1000287// permutations of the related Marshaler.
Buck Clay67cbcad2015-07-01 11:17:11 +1000288func Unmarshal(r io.Reader, pb proto.Message) error {
289 inputValue := json.RawMessage{}
290 if err := json.NewDecoder(r).Decode(&inputValue); err != nil {
291 return err
292 }
293 return unmarshalValue(reflect.ValueOf(pb).Elem(), inputValue)
294}
295
296// UnmarshalString will populate the fields of a protocol buffer based
297// on a JSON string. This function is lenient and will decode any options
David Symonds21f81362015-08-17 11:59:00 +1000298// permutations of the related Marshaler.
Buck Clay67cbcad2015-07-01 11:17:11 +1000299func UnmarshalString(str string, pb proto.Message) error {
300 return Unmarshal(bytes.NewReader([]byte(str)), pb)
301}
302
303// unmarshalValue converts/copies a value into the target.
304func unmarshalValue(target reflect.Value, inputValue json.RawMessage) error {
305 targetType := target.Type()
306
307 // Allocate memory for pointer fields.
308 if targetType.Kind() == reflect.Ptr {
309 target.Set(reflect.New(targetType.Elem()))
310 return unmarshalValue(target.Elem(), inputValue)
311 }
312
313 // Handle nested messages.
314 if targetType.Kind() == reflect.Struct {
315 var jsonFields map[string]json.RawMessage
316 if err := json.Unmarshal(inputValue, &jsonFields); err != nil {
317 return err
318 }
319
320 for i := 0; i < target.NumField(); i++ {
David Symonds31db5692015-08-10 12:45:00 +1000321 ft := target.Type().Field(i)
322 if strings.HasPrefix(ft.Name, "XXX_") {
Buck Clay67cbcad2015-07-01 11:17:11 +1000323 continue
324 }
David Symonds31db5692015-08-10 12:45:00 +1000325 fieldName := jsonFieldName(ft)
Buck Clay67cbcad2015-07-01 11:17:11 +1000326
327 if valueForField, ok := jsonFields[fieldName]; ok {
328 if err := unmarshalValue(target.Field(i), valueForField); err != nil {
329 return err
330 }
David Symonds3fe63ce2015-08-07 15:00:00 +1000331 delete(jsonFields, fieldName)
Buck Clay67cbcad2015-07-01 11:17:11 +1000332 }
333 }
David Symonds59b73b32015-08-24 13:22:02 +1000334 // Check for any oneof fields.
335 // This might be slow; we can optimise it if it becomes a problem.
336 type oneofMessage interface {
337 XXX_OneofFuncs() (func(proto.Message, *proto.Buffer) error, func(proto.Message, int, int, *proto.Buffer) (bool, error), []interface{})
338 }
339 var oneofTypes []interface{}
340 if om, ok := reflect.Zero(reflect.PtrTo(targetType)).Interface().(oneofMessage); ok {
341 _, _, oneofTypes = om.XXX_OneofFuncs()
342 }
343 for fname, raw := range jsonFields {
344 for _, oot := range oneofTypes {
345 sp := reflect.ValueOf(oot).Type() // *T
346 var props proto.Properties
347 props.Parse(sp.Elem().Field(0).Tag.Get("protobuf"))
348 if props.OrigName != fname {
349 continue
350 }
351 nv := reflect.New(sp.Elem())
352 // There will be exactly one interface field that
353 // this new value is assignable to.
354 for i := 0; i < targetType.NumField(); i++ {
355 f := targetType.Field(i)
356 if f.Type.Kind() != reflect.Interface {
357 continue
358 }
359 if !nv.Type().AssignableTo(f.Type) {
360 continue
361 }
362 target.Field(i).Set(nv)
363 break
364 }
365 if err := unmarshalValue(nv.Elem().Field(0), raw); err != nil {
366 return err
367 }
368 delete(jsonFields, fname)
369 break
370 }
371 }
David Symonds3fe63ce2015-08-07 15:00:00 +1000372 if len(jsonFields) > 0 {
373 // Pick any field to be the scapegoat.
374 var f string
375 for fname := range jsonFields {
376 f = fname
377 break
378 }
379 return fmt.Errorf("unknown field %q in %v", f, targetType)
380 }
Buck Clay67cbcad2015-07-01 11:17:11 +1000381 return nil
382 }
383
384 // Handle arrays (which aren't encoded bytes)
385 if targetType != byteArrayType && targetType.Kind() == reflect.Slice {
386 var slc []json.RawMessage
387 if err := json.Unmarshal(inputValue, &slc); err != nil {
388 return err
389 }
390 len := len(slc)
391 target.Set(reflect.MakeSlice(targetType, len, len))
392 for i := 0; i < len; i++ {
393 if err := unmarshalValue(target.Index(i), slc[i]); err != nil {
394 return err
395 }
396 }
397 return nil
398 }
399
400 // Handle maps (whose keys are always strings)
401 if targetType.Kind() == reflect.Map {
402 var mp map[string]json.RawMessage
403 if err := json.Unmarshal(inputValue, &mp); err != nil {
404 return err
405 }
406 target.Set(reflect.MakeMap(targetType))
407 for ks, raw := range mp {
408 // Unmarshal map key. The core json library already decoded the key into a
409 // string, so we handle that specially. Other types were quoted post-serialization.
410 var k reflect.Value
411 if targetType.Key().Kind() == reflect.String {
412 k = reflect.ValueOf(ks)
413 } else {
414 k = reflect.New(targetType.Key()).Elem()
415 if err := unmarshalValue(k, json.RawMessage(ks)); err != nil {
416 return err
417 }
418 }
419
420 // Unmarshal map value.
421 v := reflect.New(targetType.Elem()).Elem()
422 if err := unmarshalValue(v, raw); err != nil {
423 return err
424 }
425 target.SetMapIndex(k, v)
426 }
427 return nil
428 }
429
430 // 64-bit integers can be encoded as strings. In this case we drop
431 // the quotes and proceed as normal.
432 isNum := targetType.Kind() == reflect.Int64 || targetType.Kind() == reflect.Uint64
433 if isNum && strings.HasPrefix(string(inputValue), `"`) {
434 inputValue = inputValue[1 : len(inputValue)-1]
435 }
436
437 // Use the encoding/json for parsing other value types.
438 return json.Unmarshal(inputValue, target.Addr().Interface())
439}
440
441// hasUnmarshalJSON is a interface implemented by protocol buffer enums.
442type hasUnmarshalJSON interface {
443 UnmarshalJSON(data []byte) error
444}
445
David Symonds31db5692015-08-10 12:45:00 +1000446// jsonFieldName returns the field name to use.
447func jsonFieldName(f reflect.StructField) string {
448 var prop proto.Properties
449 prop.Init(f.Type, f.Name, f.Tag.Get("protobuf"), &f)
450 return prop.OrigName
Buck Clay67cbcad2015-07-01 11:17:11 +1000451}
452
453// Writer wrapper inspired by https://blog.golang.org/errors-are-values
454type errWriter struct {
455 writer io.Writer
456 err error
457}
458
459func (w *errWriter) write(str string) {
460 if w.err != nil {
461 return
462 }
463 _, w.err = w.writer.Write([]byte(str))
464}
465
466// Map fields may have key types of non-float scalars, strings and enums.
467// The easiest way to sort them in some deterministic order is to use fmt.
468// If this turns out to be inefficient we can always consider other options,
469// such as doing a Schwartzian transform.
470type mapKeys []reflect.Value
471
472func (s mapKeys) Len() int { return len(s) }
473func (s mapKeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
474func (s mapKeys) Less(i, j int) bool {
475 return fmt.Sprint(s[i].Interface()) < fmt.Sprint(s[j].Interface())
476}