blob: 3522ac2ba016e2b1ff7210520ed6b8cf1b7b7f5a [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 Symonds5fc22942016-01-21 14:29:00 +110033Package jsonpb provides marshaling and unmarshaling between protocol buffers and JSON.
34It follows the specification at https://developers.google.com/protocol-buffers/docs/proto3#json.
Buck Clay67cbcad2015-07-01 11:17:11 +100035
David Symonds5fc22942016-01-21 14:29:00 +110036This package produces a different output than the standard "encoding/json" package,
37which does not operate correctly on protocol buffers.
Buck Clay67cbcad2015-07-01 11:17:11 +100038*/
39package jsonpb
40
41import (
42 "bytes"
43 "encoding/json"
44 "fmt"
45 "io"
46 "reflect"
47 "sort"
48 "strconv"
49 "strings"
50
51 "github.com/golang/protobuf/proto"
52)
53
54var (
55 byteArrayType = reflect.TypeOf([]byte{})
56)
57
David Symonds21f81362015-08-17 11:59:00 +100058// Marshaler is a configurable object for converting between
David Symonds45bba202016-01-29 08:30:00 +110059// protocol buffer objects and a JSON representation for them.
David Symonds21f81362015-08-17 11:59:00 +100060type Marshaler struct {
David Symonds0ea3c032015-10-19 13:53:00 +110061 // Whether to render enum values as integers, as opposed to string values.
62 EnumsAsInts bool
63
David Symonds45bba202016-01-29 08:30:00 +110064 // Whether to render fields with zero values.
65 EmitDefaults bool
66
Buck Clay67cbcad2015-07-01 11:17:11 +100067 // A string to indent each level by. The presence of this field will
68 // also cause a space to appear between the field separator and
69 // value, and for newlines to be appear between fields and array
70 // elements.
71 Indent string
72}
73
74// Marshal marshals a protocol buffer into JSON.
David Symonds21f81362015-08-17 11:59:00 +100075func (m *Marshaler) Marshal(out io.Writer, pb proto.Message) error {
Buck Clay67cbcad2015-07-01 11:17:11 +100076 writer := &errWriter{writer: out}
77 return m.marshalObject(writer, pb, "")
78}
79
80// MarshalToString converts a protocol buffer object to JSON string.
David Symonds21f81362015-08-17 11:59:00 +100081func (m *Marshaler) MarshalToString(pb proto.Message) (string, error) {
Buck Clay67cbcad2015-07-01 11:17:11 +100082 var buf bytes.Buffer
83 if err := m.Marshal(&buf, pb); err != nil {
84 return "", err
85 }
86 return buf.String(), nil
87}
88
Juraj Stachof9dd6932015-11-03 18:47:00 +110089type int32Slice []int32
90
91// For sorting extensions ids to ensure stable output.
92func (s int32Slice) Len() int { return len(s) }
93func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] }
94func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
95
Buck Clay67cbcad2015-07-01 11:17:11 +100096// marshalObject writes a struct to the Writer.
David Symonds21f81362015-08-17 11:59:00 +100097func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent string) error {
Buck Clay67cbcad2015-07-01 11:17:11 +100098 out.write("{")
99 if m.Indent != "" {
100 out.write("\n")
101 }
102
103 s := reflect.ValueOf(v).Elem()
Juraj Stachof9dd6932015-11-03 18:47:00 +1100104 firstField := true
Buck Clay67cbcad2015-07-01 11:17:11 +1000105 for i := 0; i < s.NumField(); i++ {
106 value := s.Field(i)
107 valueField := s.Type().Field(i)
David Symonds31db5692015-08-10 12:45:00 +1000108 if strings.HasPrefix(valueField.Name, "XXX_") {
Buck Clay67cbcad2015-07-01 11:17:11 +1000109 continue
David Symonds31db5692015-08-10 12:45:00 +1000110 }
David Symonds31db5692015-08-10 12:45:00 +1000111
David Symonds31db5692015-08-10 12:45:00 +1000112 // IsNil will panic on most value kinds.
113 switch value.Kind() {
114 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
115 if value.IsNil() {
Buck Clay67cbcad2015-07-01 11:17:11 +1000116 continue
117 }
118 }
119
David Symonds45bba202016-01-29 08:30:00 +1100120 if !m.EmitDefaults {
121 switch value.Kind() {
122 case reflect.Bool:
123 if !value.Bool() {
124 continue
125 }
126 case reflect.Int32, reflect.Int64:
127 if value.Int() == 0 {
128 continue
129 }
130 case reflect.Uint32, reflect.Uint64:
131 if value.Uint() == 0 {
132 continue
133 }
134 case reflect.Float32, reflect.Float64:
135 if value.Float() == 0 {
136 continue
137 }
138 case reflect.String:
139 if value.Len() == 0 {
140 continue
141 }
142 }
143 }
144
David Symonds59b73b32015-08-24 13:22:02 +1000145 // Oneof fields need special handling.
146 if valueField.Tag.Get("protobuf_oneof") != "" {
147 // value is an interface containing &T{real_value}.
148 sv := value.Elem().Elem() // interface -> *T -> T
149 value = sv.Field(0)
150 valueField = sv.Type().Field(0)
David Symonds59b73b32015-08-24 13:22:02 +1000151 }
Juraj Stachof9dd6932015-11-03 18:47:00 +1100152 prop := jsonProperties(valueField)
153 if !firstField {
154 m.writeSep(out)
Buck Clay67cbcad2015-07-01 11:17:11 +1000155 }
Juraj Stachof9dd6932015-11-03 18:47:00 +1100156 if err := m.marshalField(out, prop, value, indent); err != nil {
Buck Clay67cbcad2015-07-01 11:17:11 +1000157 return err
158 }
Juraj Stachof9dd6932015-11-03 18:47:00 +1100159 firstField = false
160 }
Buck Clay67cbcad2015-07-01 11:17:11 +1000161
Juraj Stachof9dd6932015-11-03 18:47:00 +1100162 // Handle proto2 extensions.
163 if ep, ok := v.(extendableProto); ok {
164 extensions := proto.RegisteredExtensions(v)
165 extensionMap := ep.ExtensionMap()
166 // Sort extensions for stable output.
167 ids := make([]int32, 0, len(extensionMap))
168 for id := range extensionMap {
169 ids = append(ids, id)
Buck Clay67cbcad2015-07-01 11:17:11 +1000170 }
Juraj Stachof9dd6932015-11-03 18:47:00 +1100171 sort.Sort(int32Slice(ids))
172 for _, id := range ids {
173 desc := extensions[id]
174 if desc == nil {
175 // unknown extension
176 continue
177 }
178 ext, extErr := proto.GetExtension(ep, desc)
179 if extErr != nil {
180 return extErr
181 }
182 value := reflect.ValueOf(ext)
183 var prop proto.Properties
184 prop.Parse(desc.Tag)
185 prop.OrigName = fmt.Sprintf("[%s]", desc.Name)
186 if !firstField {
187 m.writeSep(out)
188 }
189 if err := m.marshalField(out, &prop, value, indent); err != nil {
190 return err
191 }
192 firstField = false
193 }
194
Buck Clay67cbcad2015-07-01 11:17:11 +1000195 }
196
197 if m.Indent != "" {
198 out.write("\n")
199 out.write(indent)
200 }
201 out.write("}")
202 return out.err
203}
204
Juraj Stachof9dd6932015-11-03 18:47:00 +1100205func (m *Marshaler) writeSep(out *errWriter) {
206 if m.Indent != "" {
207 out.write(",\n")
208 } else {
209 out.write(",")
210 }
211}
212
213// marshalField writes field description and value to the Writer.
214func (m *Marshaler) marshalField(out *errWriter, prop *proto.Properties, v reflect.Value, indent string) error {
215 if m.Indent != "" {
216 out.write(indent)
217 out.write(m.Indent)
218 }
219 out.write(`"`)
220 out.write(prop.OrigName)
221 out.write(`":`)
222 if m.Indent != "" {
223 out.write(" ")
224 }
225 if err := m.marshalValue(out, prop, v, indent); err != nil {
226 return err
227 }
228 return nil
229}
230
Buck Clay67cbcad2015-07-01 11:17:11 +1000231// marshalValue writes the value to the Writer.
Juraj Stachof9dd6932015-11-03 18:47:00 +1100232func (m *Marshaler) marshalValue(out *errWriter, prop *proto.Properties, v reflect.Value, indent string) error {
Buck Clay67cbcad2015-07-01 11:17:11 +1000233
234 var err error
235 v = reflect.Indirect(v)
236
237 // Handle repeated elements.
238 if v.Type() != byteArrayType && v.Kind() == reflect.Slice {
239 out.write("[")
240 comma := ""
241 for i := 0; i < v.Len(); i++ {
242 sliceVal := v.Index(i)
243 out.write(comma)
244 if m.Indent != "" {
245 out.write("\n")
246 out.write(indent)
247 out.write(m.Indent)
248 out.write(m.Indent)
249 }
Juraj Stachof9dd6932015-11-03 18:47:00 +1100250 m.marshalValue(out, prop, sliceVal, indent+m.Indent)
Buck Clay67cbcad2015-07-01 11:17:11 +1000251 comma = ","
252 }
253 if m.Indent != "" {
254 out.write("\n")
255 out.write(indent)
256 out.write(m.Indent)
257 }
258 out.write("]")
259 return out.err
260 }
261
262 // Handle enumerations.
Juraj Stachof9dd6932015-11-03 18:47:00 +1100263 if !m.EnumsAsInts && prop.Enum != "" {
Buck Clay67cbcad2015-07-01 11:17:11 +1000264 // Unknown enum values will are stringified by the proto library as their
David Symonds0ea3c032015-10-19 13:53:00 +1100265 // value. Such values should _not_ be quoted or they will be interpreted
Buck Clay67cbcad2015-07-01 11:17:11 +1000266 // as an enum string instead of their value.
267 enumStr := v.Interface().(fmt.Stringer).String()
268 var valStr string
269 if v.Kind() == reflect.Ptr {
270 valStr = strconv.Itoa(int(v.Elem().Int()))
271 } else {
272 valStr = strconv.Itoa(int(v.Int()))
273 }
274 isKnownEnum := enumStr != valStr
275 if isKnownEnum {
276 out.write(`"`)
277 }
278 out.write(enumStr)
279 if isKnownEnum {
280 out.write(`"`)
281 }
282 return out.err
283 }
284
285 // Handle nested messages.
286 if v.Kind() == reflect.Struct {
287 return m.marshalObject(out, v.Addr().Interface().(proto.Message), indent+m.Indent)
288 }
289
290 // Handle maps.
David Symonds3fe63ce2015-08-07 15:00:00 +1000291 // Since Go randomizes map iteration, we sort keys for stable output.
Buck Clay67cbcad2015-07-01 11:17:11 +1000292 if v.Kind() == reflect.Map {
293 out.write(`{`)
294 keys := v.MapKeys()
295 sort.Sort(mapKeys(keys))
296 for i, k := range keys {
297 if i > 0 {
298 out.write(`,`)
299 }
300 if m.Indent != "" {
301 out.write("\n")
302 out.write(indent)
303 out.write(m.Indent)
304 out.write(m.Indent)
305 }
306
307 b, err := json.Marshal(k.Interface())
308 if err != nil {
309 return err
310 }
311 s := string(b)
312
313 // If the JSON is not a string value, encode it again to make it one.
314 if !strings.HasPrefix(s, `"`) {
315 b, err := json.Marshal(s)
316 if err != nil {
317 return err
318 }
319 s = string(b)
320 }
321
322 out.write(s)
323 out.write(`:`)
324 if m.Indent != "" {
325 out.write(` `)
326 }
327
Juraj Stachof9dd6932015-11-03 18:47:00 +1100328 if err := m.marshalValue(out, prop, v.MapIndex(k), indent+m.Indent); err != nil {
Buck Clay67cbcad2015-07-01 11:17:11 +1000329 return err
330 }
331 }
332 if m.Indent != "" {
333 out.write("\n")
334 out.write(indent)
335 out.write(m.Indent)
336 }
337 out.write(`}`)
338 return out.err
339 }
340
341 // Default handling defers to the encoding/json library.
342 b, err := json.Marshal(v.Interface())
343 if err != nil {
344 return err
345 }
346 needToQuote := string(b[0]) != `"` && (v.Kind() == reflect.Int64 || v.Kind() == reflect.Uint64)
347 if needToQuote {
348 out.write(`"`)
349 }
350 out.write(string(b))
351 if needToQuote {
352 out.write(`"`)
353 }
354 return out.err
355}
356
357// Unmarshal unmarshals a JSON object stream into a protocol
358// buffer. This function is lenient and will decode any options
David Symonds21f81362015-08-17 11:59:00 +1000359// permutations of the related Marshaler.
Buck Clay67cbcad2015-07-01 11:17:11 +1000360func Unmarshal(r io.Reader, pb proto.Message) error {
361 inputValue := json.RawMessage{}
362 if err := json.NewDecoder(r).Decode(&inputValue); err != nil {
363 return err
364 }
365 return unmarshalValue(reflect.ValueOf(pb).Elem(), inputValue)
366}
367
368// UnmarshalString will populate the fields of a protocol buffer based
369// on a JSON string. This function is lenient and will decode any options
David Symonds21f81362015-08-17 11:59:00 +1000370// permutations of the related Marshaler.
Buck Clay67cbcad2015-07-01 11:17:11 +1000371func UnmarshalString(str string, pb proto.Message) error {
David Symonds5d7f79b2015-10-19 11:37:00 +1100372 return Unmarshal(strings.NewReader(str), pb)
Buck Clay67cbcad2015-07-01 11:17:11 +1000373}
374
375// unmarshalValue converts/copies a value into the target.
376func unmarshalValue(target reflect.Value, inputValue json.RawMessage) error {
377 targetType := target.Type()
378
379 // Allocate memory for pointer fields.
380 if targetType.Kind() == reflect.Ptr {
381 target.Set(reflect.New(targetType.Elem()))
382 return unmarshalValue(target.Elem(), inputValue)
383 }
384
385 // Handle nested messages.
386 if targetType.Kind() == reflect.Struct {
387 var jsonFields map[string]json.RawMessage
388 if err := json.Unmarshal(inputValue, &jsonFields); err != nil {
389 return err
390 }
391
David Symonds5d7f79b2015-10-19 11:37:00 +1100392 sprops := proto.GetProperties(targetType)
Buck Clay67cbcad2015-07-01 11:17:11 +1000393 for i := 0; i < target.NumField(); i++ {
David Symonds31db5692015-08-10 12:45:00 +1000394 ft := target.Type().Field(i)
395 if strings.HasPrefix(ft.Name, "XXX_") {
Buck Clay67cbcad2015-07-01 11:17:11 +1000396 continue
397 }
Juraj Stachof9dd6932015-11-03 18:47:00 +1100398 fieldName := jsonProperties(ft).OrigName
Buck Clay67cbcad2015-07-01 11:17:11 +1000399
David Symonds5d7f79b2015-10-19 11:37:00 +1100400 valueForField, ok := jsonFields[fieldName]
401 if !ok {
402 continue
403 }
404 delete(jsonFields, fieldName)
405
406 // Handle enums, which have an underlying type of int32,
407 // and may appear as strings. We do this while handling
408 // the struct so we have access to the enum info.
409 // The case of an enum appearing as a number is handled
410 // by the recursive call to unmarshalValue.
411 if enum := sprops.Prop[i].Enum; valueForField[0] == '"' && enum != "" {
412 vmap := proto.EnumValueMap(enum)
413 // Don't need to do unquoting; valid enum names
414 // are from a limited character set.
415 s := valueForField[1 : len(valueForField)-1]
416 n, ok := vmap[string(s)]
417 if !ok {
418 return fmt.Errorf("unknown value %q for enum %s", s, enum)
Buck Clay67cbcad2015-07-01 11:17:11 +1000419 }
David Symonds5d7f79b2015-10-19 11:37:00 +1100420 f := target.Field(i)
421 if f.Kind() == reflect.Ptr { // proto2
422 f.Set(reflect.New(f.Type().Elem()))
423 f = f.Elem()
424 }
425 f.SetInt(int64(n))
426 continue
427 }
428
429 if err := unmarshalValue(target.Field(i), valueForField); err != nil {
430 return err
Buck Clay67cbcad2015-07-01 11:17:11 +1000431 }
432 }
David Symonds59b73b32015-08-24 13:22:02 +1000433 // Check for any oneof fields.
David Symonds59b73b32015-08-24 13:22:02 +1000434 for fname, raw := range jsonFields {
David Symonds1baed092015-08-25 15:42:00 +1000435 if oop, ok := sprops.OneofTypes[fname]; ok {
436 nv := reflect.New(oop.Type.Elem())
437 target.Field(oop.Field).Set(nv)
David Symonds59b73b32015-08-24 13:22:02 +1000438 if err := unmarshalValue(nv.Elem().Field(0), raw); err != nil {
439 return err
440 }
441 delete(jsonFields, fname)
David Symonds59b73b32015-08-24 13:22:02 +1000442 }
443 }
David Symonds3fe63ce2015-08-07 15:00:00 +1000444 if len(jsonFields) > 0 {
445 // Pick any field to be the scapegoat.
446 var f string
447 for fname := range jsonFields {
448 f = fname
449 break
450 }
451 return fmt.Errorf("unknown field %q in %v", f, targetType)
452 }
Buck Clay67cbcad2015-07-01 11:17:11 +1000453 return nil
454 }
455
456 // Handle arrays (which aren't encoded bytes)
457 if targetType != byteArrayType && targetType.Kind() == reflect.Slice {
458 var slc []json.RawMessage
459 if err := json.Unmarshal(inputValue, &slc); err != nil {
460 return err
461 }
462 len := len(slc)
463 target.Set(reflect.MakeSlice(targetType, len, len))
464 for i := 0; i < len; i++ {
465 if err := unmarshalValue(target.Index(i), slc[i]); err != nil {
466 return err
467 }
468 }
469 return nil
470 }
471
472 // Handle maps (whose keys are always strings)
473 if targetType.Kind() == reflect.Map {
474 var mp map[string]json.RawMessage
475 if err := json.Unmarshal(inputValue, &mp); err != nil {
476 return err
477 }
478 target.Set(reflect.MakeMap(targetType))
479 for ks, raw := range mp {
480 // Unmarshal map key. The core json library already decoded the key into a
481 // string, so we handle that specially. Other types were quoted post-serialization.
482 var k reflect.Value
483 if targetType.Key().Kind() == reflect.String {
484 k = reflect.ValueOf(ks)
485 } else {
486 k = reflect.New(targetType.Key()).Elem()
487 if err := unmarshalValue(k, json.RawMessage(ks)); err != nil {
488 return err
489 }
490 }
491
492 // Unmarshal map value.
493 v := reflect.New(targetType.Elem()).Elem()
494 if err := unmarshalValue(v, raw); err != nil {
495 return err
496 }
497 target.SetMapIndex(k, v)
498 }
499 return nil
500 }
501
502 // 64-bit integers can be encoded as strings. In this case we drop
503 // the quotes and proceed as normal.
504 isNum := targetType.Kind() == reflect.Int64 || targetType.Kind() == reflect.Uint64
505 if isNum && strings.HasPrefix(string(inputValue), `"`) {
506 inputValue = inputValue[1 : len(inputValue)-1]
507 }
508
509 // Use the encoding/json for parsing other value types.
510 return json.Unmarshal(inputValue, target.Addr().Interface())
511}
512
Juraj Stachof9dd6932015-11-03 18:47:00 +1100513// jsonProperties returns parsed proto.Properties for the field.
514func jsonProperties(f reflect.StructField) *proto.Properties {
David Symonds31db5692015-08-10 12:45:00 +1000515 var prop proto.Properties
516 prop.Init(f.Type, f.Name, f.Tag.Get("protobuf"), &f)
Juraj Stachof9dd6932015-11-03 18:47:00 +1100517 return &prop
518}
519
520// extendableProto is an interface implemented by any protocol buffer that may be extended.
521type extendableProto interface {
522 proto.Message
523 ExtensionRangeArray() []proto.ExtensionRange
524 ExtensionMap() map[int32]proto.Extension
Buck Clay67cbcad2015-07-01 11:17:11 +1000525}
526
527// Writer wrapper inspired by https://blog.golang.org/errors-are-values
528type errWriter struct {
529 writer io.Writer
530 err error
531}
532
533func (w *errWriter) write(str string) {
534 if w.err != nil {
535 return
536 }
537 _, w.err = w.writer.Write([]byte(str))
538}
539
540// Map fields may have key types of non-float scalars, strings and enums.
541// The easiest way to sort them in some deterministic order is to use fmt.
542// If this turns out to be inefficient we can always consider other options,
543// such as doing a Schwartzian transform.
544type mapKeys []reflect.Value
545
546func (s mapKeys) Len() int { return len(s) }
547func (s mapKeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
548func (s mapKeys) Less(i, j int) bool {
549 return fmt.Sprint(s[i].Interface()) < fmt.Sprint(s[j].Interface())
550}