blob: c4094ac35fc9bdda3b5acf939f409d89ff46c2cc [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"
David Symonds552c7b92016-02-26 12:45:00 +110044 "errors"
Buck Clay67cbcad2015-07-01 11:17:11 +100045 "fmt"
46 "io"
47 "reflect"
48 "sort"
49 "strconv"
50 "strings"
David Symonds553c7642016-02-23 14:14:00 +110051 "time"
Buck Clay67cbcad2015-07-01 11:17:11 +100052
53 "github.com/golang/protobuf/proto"
54)
55
56var (
57 byteArrayType = reflect.TypeOf([]byte{})
58)
59
David Symonds21f81362015-08-17 11:59:00 +100060// Marshaler is a configurable object for converting between
David Symonds45bba202016-01-29 08:30:00 +110061// protocol buffer objects and a JSON representation for them.
David Symonds21f81362015-08-17 11:59:00 +100062type Marshaler struct {
David Symonds0ea3c032015-10-19 13:53:00 +110063 // Whether to render enum values as integers, as opposed to string values.
64 EnumsAsInts bool
65
David Symonds45bba202016-01-29 08:30:00 +110066 // Whether to render fields with zero values.
67 EmitDefaults bool
68
Buck Clay67cbcad2015-07-01 11:17:11 +100069 // A string to indent each level by. The presence of this field will
70 // also cause a space to appear between the field separator and
71 // value, and for newlines to be appear between fields and array
72 // elements.
73 Indent string
David Symonds001690d2016-02-10 14:04:11 +110074
75 // Whether to use the original (.proto) name for fields.
76 OrigName bool
Buck Clay67cbcad2015-07-01 11:17:11 +100077}
78
79// Marshal marshals a protocol buffer into JSON.
David Symonds21f81362015-08-17 11:59:00 +100080func (m *Marshaler) Marshal(out io.Writer, pb proto.Message) error {
Buck Clay67cbcad2015-07-01 11:17:11 +100081 writer := &errWriter{writer: out}
82 return m.marshalObject(writer, pb, "")
83}
84
85// MarshalToString converts a protocol buffer object to JSON string.
David Symonds21f81362015-08-17 11:59:00 +100086func (m *Marshaler) MarshalToString(pb proto.Message) (string, error) {
Buck Clay67cbcad2015-07-01 11:17:11 +100087 var buf bytes.Buffer
88 if err := m.Marshal(&buf, pb); err != nil {
89 return "", err
90 }
91 return buf.String(), nil
92}
93
Juraj Stachof9dd6932015-11-03 18:47:00 +110094type int32Slice []int32
95
96// For sorting extensions ids to ensure stable output.
97func (s int32Slice) Len() int { return len(s) }
98func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] }
99func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
100
Buck Clay67cbcad2015-07-01 11:17:11 +1000101// marshalObject writes a struct to the Writer.
David Symonds21f81362015-08-17 11:59:00 +1000102func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent string) error {
David Symonds553c7642016-02-23 14:14:00 +1100103 s := reflect.ValueOf(v).Elem()
104
105 // Handle well-known types.
106 type wkt interface {
107 XXX_WellKnownType() string
108 }
109 if wkt, ok := v.(wkt); ok {
110 switch wkt.XXX_WellKnownType() {
David Symondsc6184d32016-02-25 11:12:00 +1100111 case "DoubleValue", "FloatValue", "Int64Value", "UInt64Value",
112 "Int32Value", "UInt32Value", "BoolValue", "StringValue", "BytesValue":
113 // "Wrappers use the same representation in JSON
114 // as the wrapped primitive type, ..."
115 sprop := proto.GetProperties(s.Type())
116 return m.marshalValue(out, sprop.Prop[0], s.Field(0), indent)
David Symonds553c7642016-02-23 14:14:00 +1100117 case "Duration":
118 // "Generated output always contains 3, 6, or 9 fractional digits,
119 // depending on required precision."
120 s, ns := s.Field(0).Int(), s.Field(1).Int()
121 d := time.Duration(s)*time.Second + time.Duration(ns)*time.Nanosecond
122 x := fmt.Sprintf("%.9f", d.Seconds())
123 x = strings.TrimSuffix(x, "000")
124 x = strings.TrimSuffix(x, "000")
125 out.write(`"`)
126 out.write(x)
127 out.write(`s"`)
128 return out.err
David Symonds552c7b92016-02-26 12:45:00 +1100129 case "Struct":
130 // Let marshalValue handle the `fields` map.
131 // TODO: pass the correct Properties if needed.
132 return m.marshalValue(out, &proto.Properties{}, s.Field(0), indent)
David Symonds553c7642016-02-23 14:14:00 +1100133 case "Timestamp":
134 // "RFC 3339, where generated output will always be Z-normalized
135 // and uses 3, 6 or 9 fractional digits."
136 s, ns := s.Field(0).Int(), s.Field(1).Int()
137 t := time.Unix(s, ns).UTC()
138 // time.RFC3339Nano isn't exactly right (we need to get 3/6/9 fractional digits).
139 x := t.Format("2006-01-02T15:04:05.000000000")
140 x = strings.TrimSuffix(x, "000")
141 x = strings.TrimSuffix(x, "000")
142 out.write(`"`)
143 out.write(x)
144 out.write(`Z"`)
145 return out.err
David Symonds552c7b92016-02-26 12:45:00 +1100146 case "Value":
147 // Value has a single oneof.
148 kind := s.Field(0)
149 if kind.IsNil() {
150 // "absence of any variant indicates an error"
151 return errors.New("nil Value")
152 }
153 // oneof -> *T -> T -> T.F
154 x := kind.Elem().Elem().Field(0)
155 // TODO: pass the correct Properties if needed.
156 return m.marshalValue(out, &proto.Properties{}, x, indent)
David Symonds553c7642016-02-23 14:14:00 +1100157 }
158 }
159
Buck Clay67cbcad2015-07-01 11:17:11 +1000160 out.write("{")
161 if m.Indent != "" {
162 out.write("\n")
163 }
164
Juraj Stachof9dd6932015-11-03 18:47:00 +1100165 firstField := true
Buck Clay67cbcad2015-07-01 11:17:11 +1000166 for i := 0; i < s.NumField(); i++ {
167 value := s.Field(i)
168 valueField := s.Type().Field(i)
David Symonds31db5692015-08-10 12:45:00 +1000169 if strings.HasPrefix(valueField.Name, "XXX_") {
Buck Clay67cbcad2015-07-01 11:17:11 +1000170 continue
David Symonds31db5692015-08-10 12:45:00 +1000171 }
David Symonds31db5692015-08-10 12:45:00 +1000172
David Symonds31db5692015-08-10 12:45:00 +1000173 // IsNil will panic on most value kinds.
174 switch value.Kind() {
175 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
176 if value.IsNil() {
Buck Clay67cbcad2015-07-01 11:17:11 +1000177 continue
178 }
179 }
180
David Symonds45bba202016-01-29 08:30:00 +1100181 if !m.EmitDefaults {
182 switch value.Kind() {
183 case reflect.Bool:
184 if !value.Bool() {
185 continue
186 }
187 case reflect.Int32, reflect.Int64:
188 if value.Int() == 0 {
189 continue
190 }
191 case reflect.Uint32, reflect.Uint64:
192 if value.Uint() == 0 {
193 continue
194 }
195 case reflect.Float32, reflect.Float64:
196 if value.Float() == 0 {
197 continue
198 }
199 case reflect.String:
200 if value.Len() == 0 {
201 continue
202 }
203 }
204 }
205
David Symonds59b73b32015-08-24 13:22:02 +1000206 // Oneof fields need special handling.
207 if valueField.Tag.Get("protobuf_oneof") != "" {
208 // value is an interface containing &T{real_value}.
209 sv := value.Elem().Elem() // interface -> *T -> T
210 value = sv.Field(0)
211 valueField = sv.Type().Field(0)
David Symonds59b73b32015-08-24 13:22:02 +1000212 }
David Symonds001690d2016-02-10 14:04:11 +1100213 prop := jsonProperties(valueField, m.OrigName)
Juraj Stachof9dd6932015-11-03 18:47:00 +1100214 if !firstField {
215 m.writeSep(out)
Buck Clay67cbcad2015-07-01 11:17:11 +1000216 }
Juraj Stachof9dd6932015-11-03 18:47:00 +1100217 if err := m.marshalField(out, prop, value, indent); err != nil {
Buck Clay67cbcad2015-07-01 11:17:11 +1000218 return err
219 }
Juraj Stachof9dd6932015-11-03 18:47:00 +1100220 firstField = false
221 }
Buck Clay67cbcad2015-07-01 11:17:11 +1000222
Juraj Stachof9dd6932015-11-03 18:47:00 +1100223 // Handle proto2 extensions.
224 if ep, ok := v.(extendableProto); ok {
225 extensions := proto.RegisteredExtensions(v)
226 extensionMap := ep.ExtensionMap()
227 // Sort extensions for stable output.
228 ids := make([]int32, 0, len(extensionMap))
229 for id := range extensionMap {
230 ids = append(ids, id)
Buck Clay67cbcad2015-07-01 11:17:11 +1000231 }
Juraj Stachof9dd6932015-11-03 18:47:00 +1100232 sort.Sort(int32Slice(ids))
233 for _, id := range ids {
234 desc := extensions[id]
235 if desc == nil {
236 // unknown extension
237 continue
238 }
239 ext, extErr := proto.GetExtension(ep, desc)
240 if extErr != nil {
241 return extErr
242 }
243 value := reflect.ValueOf(ext)
244 var prop proto.Properties
245 prop.Parse(desc.Tag)
David Symonds001690d2016-02-10 14:04:11 +1100246 prop.JSONName = fmt.Sprintf("[%s]", desc.Name)
Juraj Stachof9dd6932015-11-03 18:47:00 +1100247 if !firstField {
248 m.writeSep(out)
249 }
250 if err := m.marshalField(out, &prop, value, indent); err != nil {
251 return err
252 }
253 firstField = false
254 }
255
Buck Clay67cbcad2015-07-01 11:17:11 +1000256 }
257
258 if m.Indent != "" {
259 out.write("\n")
260 out.write(indent)
261 }
262 out.write("}")
263 return out.err
264}
265
Juraj Stachof9dd6932015-11-03 18:47:00 +1100266func (m *Marshaler) writeSep(out *errWriter) {
267 if m.Indent != "" {
268 out.write(",\n")
269 } else {
270 out.write(",")
271 }
272}
273
274// marshalField writes field description and value to the Writer.
275func (m *Marshaler) marshalField(out *errWriter, prop *proto.Properties, v reflect.Value, indent string) error {
276 if m.Indent != "" {
277 out.write(indent)
278 out.write(m.Indent)
279 }
280 out.write(`"`)
David Symonds001690d2016-02-10 14:04:11 +1100281 out.write(prop.JSONName)
Juraj Stachof9dd6932015-11-03 18:47:00 +1100282 out.write(`":`)
283 if m.Indent != "" {
284 out.write(" ")
285 }
286 if err := m.marshalValue(out, prop, v, indent); err != nil {
287 return err
288 }
289 return nil
290}
291
Buck Clay67cbcad2015-07-01 11:17:11 +1000292// marshalValue writes the value to the Writer.
Juraj Stachof9dd6932015-11-03 18:47:00 +1100293func (m *Marshaler) marshalValue(out *errWriter, prop *proto.Properties, v reflect.Value, indent string) error {
Buck Clay67cbcad2015-07-01 11:17:11 +1000294
295 var err error
296 v = reflect.Indirect(v)
297
298 // Handle repeated elements.
299 if v.Type() != byteArrayType && v.Kind() == reflect.Slice {
300 out.write("[")
301 comma := ""
302 for i := 0; i < v.Len(); i++ {
303 sliceVal := v.Index(i)
304 out.write(comma)
305 if m.Indent != "" {
306 out.write("\n")
307 out.write(indent)
308 out.write(m.Indent)
309 out.write(m.Indent)
310 }
Juraj Stachof9dd6932015-11-03 18:47:00 +1100311 m.marshalValue(out, prop, sliceVal, indent+m.Indent)
Buck Clay67cbcad2015-07-01 11:17:11 +1000312 comma = ","
313 }
314 if m.Indent != "" {
315 out.write("\n")
316 out.write(indent)
317 out.write(m.Indent)
318 }
319 out.write("]")
320 return out.err
321 }
322
David Symonds552c7b92016-02-26 12:45:00 +1100323 // Handle well-known types.
324 // Most are handled up in marshalObject (because 99% are messages).
325 type wkt interface {
326 XXX_WellKnownType() string
327 }
328 if wkt, ok := v.Interface().(wkt); ok {
329 switch wkt.XXX_WellKnownType() {
330 case "NullValue":
331 out.write("null")
332 return out.err
333 }
334 }
335
Buck Clay67cbcad2015-07-01 11:17:11 +1000336 // Handle enumerations.
Juraj Stachof9dd6932015-11-03 18:47:00 +1100337 if !m.EnumsAsInts && prop.Enum != "" {
Buck Clay67cbcad2015-07-01 11:17:11 +1000338 // Unknown enum values will are stringified by the proto library as their
David Symonds0ea3c032015-10-19 13:53:00 +1100339 // value. Such values should _not_ be quoted or they will be interpreted
Buck Clay67cbcad2015-07-01 11:17:11 +1000340 // as an enum string instead of their value.
341 enumStr := v.Interface().(fmt.Stringer).String()
342 var valStr string
343 if v.Kind() == reflect.Ptr {
344 valStr = strconv.Itoa(int(v.Elem().Int()))
345 } else {
346 valStr = strconv.Itoa(int(v.Int()))
347 }
348 isKnownEnum := enumStr != valStr
349 if isKnownEnum {
350 out.write(`"`)
351 }
352 out.write(enumStr)
353 if isKnownEnum {
354 out.write(`"`)
355 }
356 return out.err
357 }
358
359 // Handle nested messages.
360 if v.Kind() == reflect.Struct {
361 return m.marshalObject(out, v.Addr().Interface().(proto.Message), indent+m.Indent)
362 }
363
364 // Handle maps.
David Symonds3fe63ce2015-08-07 15:00:00 +1000365 // Since Go randomizes map iteration, we sort keys for stable output.
Buck Clay67cbcad2015-07-01 11:17:11 +1000366 if v.Kind() == reflect.Map {
367 out.write(`{`)
368 keys := v.MapKeys()
369 sort.Sort(mapKeys(keys))
370 for i, k := range keys {
371 if i > 0 {
372 out.write(`,`)
373 }
374 if m.Indent != "" {
375 out.write("\n")
376 out.write(indent)
377 out.write(m.Indent)
378 out.write(m.Indent)
379 }
380
381 b, err := json.Marshal(k.Interface())
382 if err != nil {
383 return err
384 }
385 s := string(b)
386
387 // If the JSON is not a string value, encode it again to make it one.
388 if !strings.HasPrefix(s, `"`) {
389 b, err := json.Marshal(s)
390 if err != nil {
391 return err
392 }
393 s = string(b)
394 }
395
396 out.write(s)
397 out.write(`:`)
398 if m.Indent != "" {
399 out.write(` `)
400 }
401
Juraj Stachof9dd6932015-11-03 18:47:00 +1100402 if err := m.marshalValue(out, prop, v.MapIndex(k), indent+m.Indent); err != nil {
Buck Clay67cbcad2015-07-01 11:17:11 +1000403 return err
404 }
405 }
406 if m.Indent != "" {
407 out.write("\n")
408 out.write(indent)
409 out.write(m.Indent)
410 }
411 out.write(`}`)
412 return out.err
413 }
414
415 // Default handling defers to the encoding/json library.
416 b, err := json.Marshal(v.Interface())
417 if err != nil {
418 return err
419 }
420 needToQuote := string(b[0]) != `"` && (v.Kind() == reflect.Int64 || v.Kind() == reflect.Uint64)
421 if needToQuote {
422 out.write(`"`)
423 }
424 out.write(string(b))
425 if needToQuote {
426 out.write(`"`)
427 }
428 return out.err
429}
430
Nikki VonHollen99511272016-03-10 21:13:00 +1100431// UnmarshalNext unmarshals the next protocol buffer from a JSON object stream.
432// This function is lenient and will decode any options permutations of the
433// related Marshaler.
434func UnmarshalNext(dec *json.Decoder, pb proto.Message) error {
435 inputValue := json.RawMessage{}
436 if err := dec.Decode(&inputValue); err != nil {
437 return err
438 }
439 return unmarshalValue(reflect.ValueOf(pb).Elem(), inputValue)
440}
441
Buck Clay67cbcad2015-07-01 11:17:11 +1000442// Unmarshal unmarshals a JSON object stream into a protocol
443// buffer. This function is lenient and will decode any options
David Symonds21f81362015-08-17 11:59:00 +1000444// permutations of the related Marshaler.
Buck Clay67cbcad2015-07-01 11:17:11 +1000445func Unmarshal(r io.Reader, pb proto.Message) error {
Nikki VonHollen99511272016-03-10 21:13:00 +1100446 dec := json.NewDecoder(r)
447 return UnmarshalNext(dec, pb)
Buck Clay67cbcad2015-07-01 11:17:11 +1000448}
449
450// UnmarshalString will populate the fields of a protocol buffer based
451// on a JSON string. This function is lenient and will decode any options
David Symonds21f81362015-08-17 11:59:00 +1000452// permutations of the related Marshaler.
Buck Clay67cbcad2015-07-01 11:17:11 +1000453func UnmarshalString(str string, pb proto.Message) error {
David Symonds5d7f79b2015-10-19 11:37:00 +1100454 return Unmarshal(strings.NewReader(str), pb)
Buck Clay67cbcad2015-07-01 11:17:11 +1000455}
456
457// unmarshalValue converts/copies a value into the target.
458func unmarshalValue(target reflect.Value, inputValue json.RawMessage) error {
459 targetType := target.Type()
460
461 // Allocate memory for pointer fields.
462 if targetType.Kind() == reflect.Ptr {
463 target.Set(reflect.New(targetType.Elem()))
464 return unmarshalValue(target.Elem(), inputValue)
465 }
466
David Symonds553c7642016-02-23 14:14:00 +1100467 // Handle well-known types.
468 type wkt interface {
469 XXX_WellKnownType() string
470 }
471 if wkt, ok := target.Addr().Interface().(wkt); ok {
472 switch wkt.XXX_WellKnownType() {
David Symondsc6184d32016-02-25 11:12:00 +1100473 case "DoubleValue", "FloatValue", "Int64Value", "UInt64Value",
474 "Int32Value", "UInt32Value", "BoolValue", "StringValue", "BytesValue":
475 // "Wrappers use the same representation in JSON
476 // as the wrapped primitive type, except that null is allowed."
477 // encoding/json will turn JSON `null` into Go `nil`,
478 // so we don't have to do any extra work.
479 return unmarshalValue(target.Field(0), inputValue)
David Symonds553c7642016-02-23 14:14:00 +1100480 case "Duration":
481 unq, err := strconv.Unquote(string(inputValue))
482 if err != nil {
483 return err
484 }
485 d, err := time.ParseDuration(unq)
486 if err != nil {
487 return fmt.Errorf("bad Duration: %v", err)
488 }
489 ns := d.Nanoseconds()
490 s := ns / 1e9
491 ns %= 1e9
492 target.Field(0).SetInt(s)
493 target.Field(1).SetInt(ns)
494 return nil
495 case "Timestamp":
496 unq, err := strconv.Unquote(string(inputValue))
497 if err != nil {
498 return err
499 }
500 t, err := time.Parse(time.RFC3339Nano, unq)
501 if err != nil {
502 return fmt.Errorf("bad Timestamp: %v", err)
503 }
504 ns := t.UnixNano()
505 s := ns / 1e9
506 ns %= 1e9
507 target.Field(0).SetInt(s)
508 target.Field(1).SetInt(ns)
509 return nil
510 }
511 }
512
Buck Clay67cbcad2015-07-01 11:17:11 +1000513 // Handle nested messages.
514 if targetType.Kind() == reflect.Struct {
515 var jsonFields map[string]json.RawMessage
516 if err := json.Unmarshal(inputValue, &jsonFields); err != nil {
517 return err
518 }
519
David Symonds62e43642016-03-17 12:31:00 +1100520 consumeField := func(prop *proto.Properties) (json.RawMessage, bool) {
521 // Be liberal in what names we accept; both orig_name and camelName are okay.
522 fieldNames := acceptedJSONFieldNames(prop)
523
524 vOrig, okOrig := jsonFields[fieldNames.orig]
525 vCamel, okCamel := jsonFields[fieldNames.camel]
526 if !okOrig && !okCamel {
527 return nil, false
528 }
529 // If, for some reason, both are present in the data, favour the camelName.
530 var raw json.RawMessage
531 if okOrig {
532 raw = vOrig
533 delete(jsonFields, fieldNames.orig)
534 }
535 if okCamel {
536 raw = vCamel
537 delete(jsonFields, fieldNames.camel)
538 }
539 return raw, true
540 }
541
David Symonds5d7f79b2015-10-19 11:37:00 +1100542 sprops := proto.GetProperties(targetType)
Buck Clay67cbcad2015-07-01 11:17:11 +1000543 for i := 0; i < target.NumField(); i++ {
David Symonds31db5692015-08-10 12:45:00 +1000544 ft := target.Type().Field(i)
545 if strings.HasPrefix(ft.Name, "XXX_") {
Buck Clay67cbcad2015-07-01 11:17:11 +1000546 continue
547 }
548
David Symonds62e43642016-03-17 12:31:00 +1100549 valueForField, ok := consumeField(sprops.Prop[i])
550 if !ok {
David Symonds5d7f79b2015-10-19 11:37:00 +1100551 continue
552 }
David Symonds5d7f79b2015-10-19 11:37:00 +1100553
554 // Handle enums, which have an underlying type of int32,
555 // and may appear as strings. We do this while handling
556 // the struct so we have access to the enum info.
557 // The case of an enum appearing as a number is handled
558 // by the recursive call to unmarshalValue.
559 if enum := sprops.Prop[i].Enum; valueForField[0] == '"' && enum != "" {
560 vmap := proto.EnumValueMap(enum)
561 // Don't need to do unquoting; valid enum names
562 // are from a limited character set.
563 s := valueForField[1 : len(valueForField)-1]
564 n, ok := vmap[string(s)]
565 if !ok {
566 return fmt.Errorf("unknown value %q for enum %s", s, enum)
Buck Clay67cbcad2015-07-01 11:17:11 +1000567 }
David Symonds5d7f79b2015-10-19 11:37:00 +1100568 f := target.Field(i)
569 if f.Kind() == reflect.Ptr { // proto2
570 f.Set(reflect.New(f.Type().Elem()))
571 f = f.Elem()
572 }
573 f.SetInt(int64(n))
574 continue
575 }
576
577 if err := unmarshalValue(target.Field(i), valueForField); err != nil {
578 return err
Buck Clay67cbcad2015-07-01 11:17:11 +1000579 }
580 }
David Symonds59b73b32015-08-24 13:22:02 +1000581 // Check for any oneof fields.
David Symonds62e43642016-03-17 12:31:00 +1100582 if len(jsonFields) > 0 {
583 for _, oop := range sprops.OneofTypes {
584 raw, ok := consumeField(oop.Prop)
585 if !ok {
586 continue
587 }
David Symonds1baed092015-08-25 15:42:00 +1000588 nv := reflect.New(oop.Type.Elem())
589 target.Field(oop.Field).Set(nv)
David Symonds59b73b32015-08-24 13:22:02 +1000590 if err := unmarshalValue(nv.Elem().Field(0), raw); err != nil {
591 return err
592 }
David Symonds59b73b32015-08-24 13:22:02 +1000593 }
594 }
David Symonds3fe63ce2015-08-07 15:00:00 +1000595 if len(jsonFields) > 0 {
596 // Pick any field to be the scapegoat.
597 var f string
598 for fname := range jsonFields {
599 f = fname
600 break
601 }
602 return fmt.Errorf("unknown field %q in %v", f, targetType)
603 }
Buck Clay67cbcad2015-07-01 11:17:11 +1000604 return nil
605 }
606
607 // Handle arrays (which aren't encoded bytes)
608 if targetType != byteArrayType && targetType.Kind() == reflect.Slice {
609 var slc []json.RawMessage
610 if err := json.Unmarshal(inputValue, &slc); err != nil {
611 return err
612 }
613 len := len(slc)
614 target.Set(reflect.MakeSlice(targetType, len, len))
615 for i := 0; i < len; i++ {
616 if err := unmarshalValue(target.Index(i), slc[i]); err != nil {
617 return err
618 }
619 }
620 return nil
621 }
622
623 // Handle maps (whose keys are always strings)
624 if targetType.Kind() == reflect.Map {
625 var mp map[string]json.RawMessage
626 if err := json.Unmarshal(inputValue, &mp); err != nil {
627 return err
628 }
629 target.Set(reflect.MakeMap(targetType))
630 for ks, raw := range mp {
631 // Unmarshal map key. The core json library already decoded the key into a
632 // string, so we handle that specially. Other types were quoted post-serialization.
633 var k reflect.Value
634 if targetType.Key().Kind() == reflect.String {
635 k = reflect.ValueOf(ks)
636 } else {
637 k = reflect.New(targetType.Key()).Elem()
638 if err := unmarshalValue(k, json.RawMessage(ks)); err != nil {
639 return err
640 }
641 }
642
643 // Unmarshal map value.
644 v := reflect.New(targetType.Elem()).Elem()
645 if err := unmarshalValue(v, raw); err != nil {
646 return err
647 }
648 target.SetMapIndex(k, v)
649 }
650 return nil
651 }
652
653 // 64-bit integers can be encoded as strings. In this case we drop
654 // the quotes and proceed as normal.
655 isNum := targetType.Kind() == reflect.Int64 || targetType.Kind() == reflect.Uint64
656 if isNum && strings.HasPrefix(string(inputValue), `"`) {
657 inputValue = inputValue[1 : len(inputValue)-1]
658 }
659
660 // Use the encoding/json for parsing other value types.
661 return json.Unmarshal(inputValue, target.Addr().Interface())
662}
663
David Symonds001690d2016-02-10 14:04:11 +1100664// jsonProperties returns parsed proto.Properties for the field and corrects JSONName attribute.
665func jsonProperties(f reflect.StructField, origName bool) *proto.Properties {
David Symonds31db5692015-08-10 12:45:00 +1000666 var prop proto.Properties
667 prop.Init(f.Type, f.Name, f.Tag.Get("protobuf"), &f)
David Symonds001690d2016-02-10 14:04:11 +1100668 if origName || prop.JSONName == "" {
669 prop.JSONName = prop.OrigName
670 }
Juraj Stachof9dd6932015-11-03 18:47:00 +1100671 return &prop
672}
673
David Symonds001690d2016-02-10 14:04:11 +1100674type fieldNames struct {
675 orig, camel string
676}
677
David Symonds62e43642016-03-17 12:31:00 +1100678func acceptedJSONFieldNames(prop *proto.Properties) fieldNames {
David Symonds001690d2016-02-10 14:04:11 +1100679 opts := fieldNames{orig: prop.OrigName, camel: prop.OrigName}
680 if prop.JSONName != "" {
681 opts.camel = prop.JSONName
682 }
683 return opts
684}
685
Juraj Stachof9dd6932015-11-03 18:47:00 +1100686// extendableProto is an interface implemented by any protocol buffer that may be extended.
687type extendableProto interface {
688 proto.Message
689 ExtensionRangeArray() []proto.ExtensionRange
690 ExtensionMap() map[int32]proto.Extension
Buck Clay67cbcad2015-07-01 11:17:11 +1000691}
692
693// Writer wrapper inspired by https://blog.golang.org/errors-are-values
694type errWriter struct {
695 writer io.Writer
696 err error
697}
698
699func (w *errWriter) write(str string) {
700 if w.err != nil {
701 return
702 }
703 _, w.err = w.writer.Write([]byte(str))
704}
705
706// Map fields may have key types of non-float scalars, strings and enums.
707// The easiest way to sort them in some deterministic order is to use fmt.
708// If this turns out to be inefficient we can always consider other options,
709// such as doing a Schwartzian transform.
710type mapKeys []reflect.Value
711
712func (s mapKeys) Len() int { return len(s) }
713func (s mapKeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
714func (s mapKeys) Less(i, j int) bool {
715 return fmt.Sprint(s[i].Interface()) < fmt.Sprint(s[j].Interface())
716}