blob: 69ed7fd0f29db2b635d7d8c3aae52b814287eb83 [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 }
David Symondsf0a097d2016-04-13 14:01:00 +1000439 return unmarshalValue(reflect.ValueOf(pb).Elem(), inputValue, nil)
Nikki VonHollen99511272016-03-10 21:13:00 +1100440}
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.
David Symondsf0a097d2016-04-13 14:01:00 +1000458// prop may be nil.
459func unmarshalValue(target reflect.Value, inputValue json.RawMessage, prop *proto.Properties) error {
Buck Clay67cbcad2015-07-01 11:17:11 +1000460 targetType := target.Type()
461
462 // Allocate memory for pointer fields.
463 if targetType.Kind() == reflect.Ptr {
464 target.Set(reflect.New(targetType.Elem()))
David Symondsf0a097d2016-04-13 14:01:00 +1000465 return unmarshalValue(target.Elem(), inputValue, prop)
Buck Clay67cbcad2015-07-01 11:17:11 +1000466 }
467
David Symonds553c7642016-02-23 14:14:00 +1100468 // Handle well-known types.
469 type wkt interface {
470 XXX_WellKnownType() string
471 }
472 if wkt, ok := target.Addr().Interface().(wkt); ok {
473 switch wkt.XXX_WellKnownType() {
David Symondsc6184d32016-02-25 11:12:00 +1100474 case "DoubleValue", "FloatValue", "Int64Value", "UInt64Value",
475 "Int32Value", "UInt32Value", "BoolValue", "StringValue", "BytesValue":
476 // "Wrappers use the same representation in JSON
477 // as the wrapped primitive type, except that null is allowed."
478 // encoding/json will turn JSON `null` into Go `nil`,
479 // so we don't have to do any extra work.
David Symondsf0a097d2016-04-13 14:01:00 +1000480 return unmarshalValue(target.Field(0), inputValue, prop)
David Symonds553c7642016-02-23 14:14:00 +1100481 case "Duration":
482 unq, err := strconv.Unquote(string(inputValue))
483 if err != nil {
484 return err
485 }
486 d, err := time.ParseDuration(unq)
487 if err != nil {
488 return fmt.Errorf("bad Duration: %v", err)
489 }
490 ns := d.Nanoseconds()
491 s := ns / 1e9
492 ns %= 1e9
493 target.Field(0).SetInt(s)
494 target.Field(1).SetInt(ns)
495 return nil
496 case "Timestamp":
497 unq, err := strconv.Unquote(string(inputValue))
498 if err != nil {
499 return err
500 }
501 t, err := time.Parse(time.RFC3339Nano, unq)
502 if err != nil {
503 return fmt.Errorf("bad Timestamp: %v", err)
504 }
505 ns := t.UnixNano()
506 s := ns / 1e9
507 ns %= 1e9
508 target.Field(0).SetInt(s)
509 target.Field(1).SetInt(ns)
510 return nil
511 }
512 }
513
David Symondsf0a097d2016-04-13 14:01:00 +1000514 // Handle enums, which have an underlying type of int32,
515 // and may appear as strings.
516 // The case of an enum appearing as a number is handled
517 // at the bottom of this function.
518 if inputValue[0] == '"' && prop != nil && prop.Enum != "" {
519 vmap := proto.EnumValueMap(prop.Enum)
520 // Don't need to do unquoting; valid enum names
521 // are from a limited character set.
522 s := inputValue[1 : len(inputValue)-1]
523 n, ok := vmap[string(s)]
524 if !ok {
525 return fmt.Errorf("unknown value %q for enum %s", s, prop.Enum)
526 }
527 if target.Kind() == reflect.Ptr { // proto2
528 target.Set(reflect.New(targetType.Elem()))
529 target = target.Elem()
530 }
531 target.SetInt(int64(n))
532 return nil
533 }
534
Buck Clay67cbcad2015-07-01 11:17:11 +1000535 // Handle nested messages.
536 if targetType.Kind() == reflect.Struct {
537 var jsonFields map[string]json.RawMessage
538 if err := json.Unmarshal(inputValue, &jsonFields); err != nil {
539 return err
540 }
541
David Symonds62e43642016-03-17 12:31:00 +1100542 consumeField := func(prop *proto.Properties) (json.RawMessage, bool) {
543 // Be liberal in what names we accept; both orig_name and camelName are okay.
544 fieldNames := acceptedJSONFieldNames(prop)
545
546 vOrig, okOrig := jsonFields[fieldNames.orig]
547 vCamel, okCamel := jsonFields[fieldNames.camel]
548 if !okOrig && !okCamel {
549 return nil, false
550 }
551 // If, for some reason, both are present in the data, favour the camelName.
552 var raw json.RawMessage
553 if okOrig {
554 raw = vOrig
555 delete(jsonFields, fieldNames.orig)
556 }
557 if okCamel {
558 raw = vCamel
559 delete(jsonFields, fieldNames.camel)
560 }
561 return raw, true
562 }
563
David Symonds5d7f79b2015-10-19 11:37:00 +1100564 sprops := proto.GetProperties(targetType)
Buck Clay67cbcad2015-07-01 11:17:11 +1000565 for i := 0; i < target.NumField(); i++ {
David Symonds31db5692015-08-10 12:45:00 +1000566 ft := target.Type().Field(i)
567 if strings.HasPrefix(ft.Name, "XXX_") {
Buck Clay67cbcad2015-07-01 11:17:11 +1000568 continue
569 }
570
David Symonds62e43642016-03-17 12:31:00 +1100571 valueForField, ok := consumeField(sprops.Prop[i])
572 if !ok {
David Symonds5d7f79b2015-10-19 11:37:00 +1100573 continue
574 }
David Symonds5d7f79b2015-10-19 11:37:00 +1100575
David Symondsf0a097d2016-04-13 14:01:00 +1000576 if err := unmarshalValue(target.Field(i), valueForField, sprops.Prop[i]); err != nil {
David Symonds5d7f79b2015-10-19 11:37:00 +1100577 return err
Buck Clay67cbcad2015-07-01 11:17:11 +1000578 }
579 }
David Symonds59b73b32015-08-24 13:22:02 +1000580 // Check for any oneof fields.
David Symonds62e43642016-03-17 12:31:00 +1100581 if len(jsonFields) > 0 {
582 for _, oop := range sprops.OneofTypes {
583 raw, ok := consumeField(oop.Prop)
584 if !ok {
585 continue
586 }
David Symonds1baed092015-08-25 15:42:00 +1000587 nv := reflect.New(oop.Type.Elem())
588 target.Field(oop.Field).Set(nv)
David Symondsf0a097d2016-04-13 14:01:00 +1000589 if err := unmarshalValue(nv.Elem().Field(0), raw, oop.Prop); err != nil {
David Symonds59b73b32015-08-24 13:22:02 +1000590 return err
591 }
David Symonds59b73b32015-08-24 13:22:02 +1000592 }
593 }
David Symonds3fe63ce2015-08-07 15:00:00 +1000594 if len(jsonFields) > 0 {
595 // Pick any field to be the scapegoat.
596 var f string
597 for fname := range jsonFields {
598 f = fname
599 break
600 }
601 return fmt.Errorf("unknown field %q in %v", f, targetType)
602 }
Buck Clay67cbcad2015-07-01 11:17:11 +1000603 return nil
604 }
605
606 // Handle arrays (which aren't encoded bytes)
607 if targetType != byteArrayType && targetType.Kind() == reflect.Slice {
608 var slc []json.RawMessage
609 if err := json.Unmarshal(inputValue, &slc); err != nil {
610 return err
611 }
612 len := len(slc)
613 target.Set(reflect.MakeSlice(targetType, len, len))
614 for i := 0; i < len; i++ {
David Symondsf0a097d2016-04-13 14:01:00 +1000615 if err := unmarshalValue(target.Index(i), slc[i], prop); err != nil {
Buck Clay67cbcad2015-07-01 11:17:11 +1000616 return err
617 }
618 }
619 return nil
620 }
621
622 // Handle maps (whose keys are always strings)
623 if targetType.Kind() == reflect.Map {
624 var mp map[string]json.RawMessage
625 if err := json.Unmarshal(inputValue, &mp); err != nil {
626 return err
627 }
628 target.Set(reflect.MakeMap(targetType))
David Symondsf0a097d2016-04-13 14:01:00 +1000629 var keyprop, valprop *proto.Properties
630 if prop != nil {
631 // These could still be nil if the protobuf metadata is broken somehow.
632 // TODO: This won't work because the fields are unexported.
633 // We should probably just reparse them.
634 //keyprop, valprop = prop.mkeyprop, prop.mvalprop
635 }
Buck Clay67cbcad2015-07-01 11:17:11 +1000636 for ks, raw := range mp {
637 // Unmarshal map key. The core json library already decoded the key into a
638 // string, so we handle that specially. Other types were quoted post-serialization.
639 var k reflect.Value
640 if targetType.Key().Kind() == reflect.String {
641 k = reflect.ValueOf(ks)
642 } else {
643 k = reflect.New(targetType.Key()).Elem()
David Symondsf0a097d2016-04-13 14:01:00 +1000644 if err := unmarshalValue(k, json.RawMessage(ks), keyprop); err != nil {
Buck Clay67cbcad2015-07-01 11:17:11 +1000645 return err
646 }
647 }
648
649 // Unmarshal map value.
650 v := reflect.New(targetType.Elem()).Elem()
David Symondsf0a097d2016-04-13 14:01:00 +1000651 if err := unmarshalValue(v, raw, valprop); err != nil {
Buck Clay67cbcad2015-07-01 11:17:11 +1000652 return err
653 }
654 target.SetMapIndex(k, v)
655 }
656 return nil
657 }
658
659 // 64-bit integers can be encoded as strings. In this case we drop
660 // the quotes and proceed as normal.
661 isNum := targetType.Kind() == reflect.Int64 || targetType.Kind() == reflect.Uint64
662 if isNum && strings.HasPrefix(string(inputValue), `"`) {
663 inputValue = inputValue[1 : len(inputValue)-1]
664 }
665
666 // Use the encoding/json for parsing other value types.
667 return json.Unmarshal(inputValue, target.Addr().Interface())
668}
669
David Symonds001690d2016-02-10 14:04:11 +1100670// jsonProperties returns parsed proto.Properties for the field and corrects JSONName attribute.
671func jsonProperties(f reflect.StructField, origName bool) *proto.Properties {
David Symonds31db5692015-08-10 12:45:00 +1000672 var prop proto.Properties
673 prop.Init(f.Type, f.Name, f.Tag.Get("protobuf"), &f)
David Symonds001690d2016-02-10 14:04:11 +1100674 if origName || prop.JSONName == "" {
675 prop.JSONName = prop.OrigName
676 }
Juraj Stachof9dd6932015-11-03 18:47:00 +1100677 return &prop
678}
679
David Symonds001690d2016-02-10 14:04:11 +1100680type fieldNames struct {
681 orig, camel string
682}
683
David Symonds62e43642016-03-17 12:31:00 +1100684func acceptedJSONFieldNames(prop *proto.Properties) fieldNames {
David Symonds001690d2016-02-10 14:04:11 +1100685 opts := fieldNames{orig: prop.OrigName, camel: prop.OrigName}
686 if prop.JSONName != "" {
687 opts.camel = prop.JSONName
688 }
689 return opts
690}
691
Juraj Stachof9dd6932015-11-03 18:47:00 +1100692// extendableProto is an interface implemented by any protocol buffer that may be extended.
693type extendableProto interface {
694 proto.Message
695 ExtensionRangeArray() []proto.ExtensionRange
696 ExtensionMap() map[int32]proto.Extension
Buck Clay67cbcad2015-07-01 11:17:11 +1000697}
698
699// Writer wrapper inspired by https://blog.golang.org/errors-are-values
700type errWriter struct {
701 writer io.Writer
702 err error
703}
704
705func (w *errWriter) write(str string) {
706 if w.err != nil {
707 return
708 }
709 _, w.err = w.writer.Write([]byte(str))
710}
711
712// Map fields may have key types of non-float scalars, strings and enums.
713// The easiest way to sort them in some deterministic order is to use fmt.
714// If this turns out to be inefficient we can always consider other options,
715// such as doing a Schwartzian transform.
716type mapKeys []reflect.Value
717
718func (s mapKeys) Len() int { return len(s) }
719func (s mapKeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
720func (s mapKeys) Less(i, j int) bool {
721 return fmt.Sprint(s[i].Interface()) < fmt.Sprint(s[j].Interface())
722}