blob: 91dcd26af573d993b74a87d78ad0f7ca06b691ab [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}
David Symondsbf531ff2016-04-20 14:40:00 +100082 return m.marshalObject(writer, pb, "", "")
Buck Clay67cbcad2015-07-01 11:17:11 +100083}
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
David Symondsbf531ff2016-04-20 14:40:00 +1000101type wkt interface {
102 XXX_WellKnownType() string
103}
104
Buck Clay67cbcad2015-07-01 11:17:11 +1000105// marshalObject writes a struct to the Writer.
David Symondsbf531ff2016-04-20 14:40:00 +1000106func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent, typeURL string) error {
David Symonds553c7642016-02-23 14:14:00 +1100107 s := reflect.ValueOf(v).Elem()
108
109 // Handle well-known types.
David Symonds553c7642016-02-23 14:14:00 +1100110 if wkt, ok := v.(wkt); ok {
111 switch wkt.XXX_WellKnownType() {
David Symondsc6184d32016-02-25 11:12:00 +1100112 case "DoubleValue", "FloatValue", "Int64Value", "UInt64Value",
113 "Int32Value", "UInt32Value", "BoolValue", "StringValue", "BytesValue":
114 // "Wrappers use the same representation in JSON
115 // as the wrapped primitive type, ..."
116 sprop := proto.GetProperties(s.Type())
117 return m.marshalValue(out, sprop.Prop[0], s.Field(0), indent)
David Symondsbf531ff2016-04-20 14:40:00 +1000118 case "Any":
119 // Any is a bit more involved.
120 return m.marshalAny(out, v, indent)
David Symonds553c7642016-02-23 14:14:00 +1100121 case "Duration":
122 // "Generated output always contains 3, 6, or 9 fractional digits,
123 // depending on required precision."
124 s, ns := s.Field(0).Int(), s.Field(1).Int()
125 d := time.Duration(s)*time.Second + time.Duration(ns)*time.Nanosecond
126 x := fmt.Sprintf("%.9f", d.Seconds())
127 x = strings.TrimSuffix(x, "000")
128 x = strings.TrimSuffix(x, "000")
129 out.write(`"`)
130 out.write(x)
131 out.write(`s"`)
132 return out.err
David Symonds552c7b92016-02-26 12:45:00 +1100133 case "Struct":
134 // Let marshalValue handle the `fields` map.
135 // TODO: pass the correct Properties if needed.
136 return m.marshalValue(out, &proto.Properties{}, s.Field(0), indent)
David Symonds553c7642016-02-23 14:14:00 +1100137 case "Timestamp":
138 // "RFC 3339, where generated output will always be Z-normalized
139 // and uses 3, 6 or 9 fractional digits."
140 s, ns := s.Field(0).Int(), s.Field(1).Int()
141 t := time.Unix(s, ns).UTC()
142 // time.RFC3339Nano isn't exactly right (we need to get 3/6/9 fractional digits).
143 x := t.Format("2006-01-02T15:04:05.000000000")
144 x = strings.TrimSuffix(x, "000")
145 x = strings.TrimSuffix(x, "000")
146 out.write(`"`)
147 out.write(x)
148 out.write(`Z"`)
149 return out.err
David Symonds552c7b92016-02-26 12:45:00 +1100150 case "Value":
151 // Value has a single oneof.
152 kind := s.Field(0)
153 if kind.IsNil() {
154 // "absence of any variant indicates an error"
155 return errors.New("nil Value")
156 }
157 // oneof -> *T -> T -> T.F
158 x := kind.Elem().Elem().Field(0)
159 // TODO: pass the correct Properties if needed.
160 return m.marshalValue(out, &proto.Properties{}, x, indent)
David Symonds553c7642016-02-23 14:14:00 +1100161 }
162 }
163
Buck Clay67cbcad2015-07-01 11:17:11 +1000164 out.write("{")
165 if m.Indent != "" {
166 out.write("\n")
167 }
168
Juraj Stachof9dd6932015-11-03 18:47:00 +1100169 firstField := true
David Symondsbf531ff2016-04-20 14:40:00 +1000170
171 if typeURL != "" {
172 if err := m.marshalTypeURL(out, indent, typeURL); err != nil {
173 return err
174 }
175 firstField = false
176 }
177
Buck Clay67cbcad2015-07-01 11:17:11 +1000178 for i := 0; i < s.NumField(); i++ {
179 value := s.Field(i)
180 valueField := s.Type().Field(i)
David Symonds31db5692015-08-10 12:45:00 +1000181 if strings.HasPrefix(valueField.Name, "XXX_") {
Buck Clay67cbcad2015-07-01 11:17:11 +1000182 continue
David Symonds31db5692015-08-10 12:45:00 +1000183 }
David Symonds31db5692015-08-10 12:45:00 +1000184
David Symonds31db5692015-08-10 12:45:00 +1000185 // IsNil will panic on most value kinds.
186 switch value.Kind() {
187 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
188 if value.IsNil() {
Buck Clay67cbcad2015-07-01 11:17:11 +1000189 continue
190 }
191 }
192
David Symonds45bba202016-01-29 08:30:00 +1100193 if !m.EmitDefaults {
194 switch value.Kind() {
195 case reflect.Bool:
196 if !value.Bool() {
197 continue
198 }
199 case reflect.Int32, reflect.Int64:
200 if value.Int() == 0 {
201 continue
202 }
203 case reflect.Uint32, reflect.Uint64:
204 if value.Uint() == 0 {
205 continue
206 }
207 case reflect.Float32, reflect.Float64:
208 if value.Float() == 0 {
209 continue
210 }
211 case reflect.String:
212 if value.Len() == 0 {
213 continue
214 }
215 }
216 }
217
David Symonds59b73b32015-08-24 13:22:02 +1000218 // Oneof fields need special handling.
219 if valueField.Tag.Get("protobuf_oneof") != "" {
220 // value is an interface containing &T{real_value}.
221 sv := value.Elem().Elem() // interface -> *T -> T
222 value = sv.Field(0)
223 valueField = sv.Type().Field(0)
David Symonds59b73b32015-08-24 13:22:02 +1000224 }
David Symonds001690d2016-02-10 14:04:11 +1100225 prop := jsonProperties(valueField, m.OrigName)
Juraj Stachof9dd6932015-11-03 18:47:00 +1100226 if !firstField {
227 m.writeSep(out)
Buck Clay67cbcad2015-07-01 11:17:11 +1000228 }
Juraj Stachof9dd6932015-11-03 18:47:00 +1100229 if err := m.marshalField(out, prop, value, indent); err != nil {
Buck Clay67cbcad2015-07-01 11:17:11 +1000230 return err
231 }
Juraj Stachof9dd6932015-11-03 18:47:00 +1100232 firstField = false
233 }
Buck Clay67cbcad2015-07-01 11:17:11 +1000234
Juraj Stachof9dd6932015-11-03 18:47:00 +1100235 // Handle proto2 extensions.
236 if ep, ok := v.(extendableProto); ok {
237 extensions := proto.RegisteredExtensions(v)
238 extensionMap := ep.ExtensionMap()
239 // Sort extensions for stable output.
240 ids := make([]int32, 0, len(extensionMap))
241 for id := range extensionMap {
242 ids = append(ids, id)
Buck Clay67cbcad2015-07-01 11:17:11 +1000243 }
Juraj Stachof9dd6932015-11-03 18:47:00 +1100244 sort.Sort(int32Slice(ids))
245 for _, id := range ids {
246 desc := extensions[id]
247 if desc == nil {
248 // unknown extension
249 continue
250 }
251 ext, extErr := proto.GetExtension(ep, desc)
252 if extErr != nil {
253 return extErr
254 }
255 value := reflect.ValueOf(ext)
256 var prop proto.Properties
257 prop.Parse(desc.Tag)
David Symonds001690d2016-02-10 14:04:11 +1100258 prop.JSONName = fmt.Sprintf("[%s]", desc.Name)
Juraj Stachof9dd6932015-11-03 18:47:00 +1100259 if !firstField {
260 m.writeSep(out)
261 }
262 if err := m.marshalField(out, &prop, value, indent); err != nil {
263 return err
264 }
265 firstField = false
266 }
267
Buck Clay67cbcad2015-07-01 11:17:11 +1000268 }
269
270 if m.Indent != "" {
271 out.write("\n")
272 out.write(indent)
273 }
274 out.write("}")
275 return out.err
276}
277
Juraj Stachof9dd6932015-11-03 18:47:00 +1100278func (m *Marshaler) writeSep(out *errWriter) {
279 if m.Indent != "" {
280 out.write(",\n")
281 } else {
282 out.write(",")
283 }
284}
285
David Symondsbf531ff2016-04-20 14:40:00 +1000286func (m *Marshaler) marshalAny(out *errWriter, any proto.Message, indent string) error {
287 // "If the Any contains a value that has a special JSON mapping,
288 // it will be converted as follows: {"@type": xxx, "value": yyy}.
289 // Otherwise, the value will be converted into a JSON object,
290 // and the "@type" field will be inserted to indicate the actual data type."
291 v := reflect.ValueOf(any).Elem()
292 turl := v.Field(0).String()
293 val := v.Field(1).Bytes()
294
295 // Only the part of type_url after the last slash is relevant.
296 mname := turl
297 if slash := strings.LastIndex(mname, "/"); slash >= 0 {
298 mname = mname[slash+1:]
299 }
300 mt := proto.MessageType(mname)
301 if mt == nil {
302 return fmt.Errorf("unknown message type %q", mname)
303 }
304 msg := reflect.New(mt.Elem()).Interface().(proto.Message)
305 if err := proto.Unmarshal(val, msg); err != nil {
306 return err
307 }
308
309 if _, ok := msg.(wkt); ok {
310 out.write("{")
311 if m.Indent != "" {
312 out.write("\n")
313 }
314 if err := m.marshalTypeURL(out, indent, turl); err != nil {
315 return err
316 }
317 m.writeSep(out)
318 out.write(`"value":`)
319 if err := m.marshalObject(out, msg, indent, ""); err != nil {
320 return err
321 }
322 if m.Indent != "" {
323 out.write("\n")
324 out.write(indent)
325 }
326 out.write("}")
327 return out.err
328 }
329
330 return m.marshalObject(out, msg, indent, turl)
331}
332
333func (m *Marshaler) marshalTypeURL(out *errWriter, indent, typeURL string) error {
334 if m.Indent != "" {
335 out.write(indent)
336 out.write(m.Indent)
337 }
338 out.write(`"@type":`)
339 if m.Indent != "" {
340 out.write(" ")
341 }
342 b, err := json.Marshal(typeURL)
343 if err != nil {
344 return err
345 }
346 out.write(string(b))
347 return out.err
348}
349
Juraj Stachof9dd6932015-11-03 18:47:00 +1100350// marshalField writes field description and value to the Writer.
351func (m *Marshaler) marshalField(out *errWriter, prop *proto.Properties, v reflect.Value, indent string) error {
352 if m.Indent != "" {
353 out.write(indent)
354 out.write(m.Indent)
355 }
356 out.write(`"`)
David Symonds001690d2016-02-10 14:04:11 +1100357 out.write(prop.JSONName)
Juraj Stachof9dd6932015-11-03 18:47:00 +1100358 out.write(`":`)
359 if m.Indent != "" {
360 out.write(" ")
361 }
362 if err := m.marshalValue(out, prop, v, indent); err != nil {
363 return err
364 }
365 return nil
366}
367
Buck Clay67cbcad2015-07-01 11:17:11 +1000368// marshalValue writes the value to the Writer.
Juraj Stachof9dd6932015-11-03 18:47:00 +1100369func (m *Marshaler) marshalValue(out *errWriter, prop *proto.Properties, v reflect.Value, indent string) error {
Buck Clay67cbcad2015-07-01 11:17:11 +1000370
371 var err error
372 v = reflect.Indirect(v)
373
374 // Handle repeated elements.
375 if v.Type() != byteArrayType && v.Kind() == reflect.Slice {
376 out.write("[")
377 comma := ""
378 for i := 0; i < v.Len(); i++ {
379 sliceVal := v.Index(i)
380 out.write(comma)
381 if m.Indent != "" {
382 out.write("\n")
383 out.write(indent)
384 out.write(m.Indent)
385 out.write(m.Indent)
386 }
Juraj Stachof9dd6932015-11-03 18:47:00 +1100387 m.marshalValue(out, prop, sliceVal, indent+m.Indent)
Buck Clay67cbcad2015-07-01 11:17:11 +1000388 comma = ","
389 }
390 if m.Indent != "" {
391 out.write("\n")
392 out.write(indent)
393 out.write(m.Indent)
394 }
395 out.write("]")
396 return out.err
397 }
398
David Symonds552c7b92016-02-26 12:45:00 +1100399 // Handle well-known types.
400 // Most are handled up in marshalObject (because 99% are messages).
401 type wkt interface {
402 XXX_WellKnownType() string
403 }
404 if wkt, ok := v.Interface().(wkt); ok {
405 switch wkt.XXX_WellKnownType() {
406 case "NullValue":
407 out.write("null")
408 return out.err
409 }
410 }
411
Buck Clay67cbcad2015-07-01 11:17:11 +1000412 // Handle enumerations.
Juraj Stachof9dd6932015-11-03 18:47:00 +1100413 if !m.EnumsAsInts && prop.Enum != "" {
Buck Clay67cbcad2015-07-01 11:17:11 +1000414 // Unknown enum values will are stringified by the proto library as their
David Symonds0ea3c032015-10-19 13:53:00 +1100415 // value. Such values should _not_ be quoted or they will be interpreted
Buck Clay67cbcad2015-07-01 11:17:11 +1000416 // as an enum string instead of their value.
417 enumStr := v.Interface().(fmt.Stringer).String()
418 var valStr string
419 if v.Kind() == reflect.Ptr {
420 valStr = strconv.Itoa(int(v.Elem().Int()))
421 } else {
422 valStr = strconv.Itoa(int(v.Int()))
423 }
424 isKnownEnum := enumStr != valStr
425 if isKnownEnum {
426 out.write(`"`)
427 }
428 out.write(enumStr)
429 if isKnownEnum {
430 out.write(`"`)
431 }
432 return out.err
433 }
434
435 // Handle nested messages.
436 if v.Kind() == reflect.Struct {
David Symondsbf531ff2016-04-20 14:40:00 +1000437 return m.marshalObject(out, v.Addr().Interface().(proto.Message), indent+m.Indent, "")
Buck Clay67cbcad2015-07-01 11:17:11 +1000438 }
439
440 // Handle maps.
David Symonds3fe63ce2015-08-07 15:00:00 +1000441 // Since Go randomizes map iteration, we sort keys for stable output.
Buck Clay67cbcad2015-07-01 11:17:11 +1000442 if v.Kind() == reflect.Map {
443 out.write(`{`)
444 keys := v.MapKeys()
445 sort.Sort(mapKeys(keys))
446 for i, k := range keys {
447 if i > 0 {
448 out.write(`,`)
449 }
450 if m.Indent != "" {
451 out.write("\n")
452 out.write(indent)
453 out.write(m.Indent)
454 out.write(m.Indent)
455 }
456
457 b, err := json.Marshal(k.Interface())
458 if err != nil {
459 return err
460 }
461 s := string(b)
462
463 // If the JSON is not a string value, encode it again to make it one.
464 if !strings.HasPrefix(s, `"`) {
465 b, err := json.Marshal(s)
466 if err != nil {
467 return err
468 }
469 s = string(b)
470 }
471
472 out.write(s)
473 out.write(`:`)
474 if m.Indent != "" {
475 out.write(` `)
476 }
477
Juraj Stachof9dd6932015-11-03 18:47:00 +1100478 if err := m.marshalValue(out, prop, v.MapIndex(k), indent+m.Indent); err != nil {
Buck Clay67cbcad2015-07-01 11:17:11 +1000479 return err
480 }
481 }
482 if m.Indent != "" {
483 out.write("\n")
484 out.write(indent)
485 out.write(m.Indent)
486 }
487 out.write(`}`)
488 return out.err
489 }
490
491 // Default handling defers to the encoding/json library.
492 b, err := json.Marshal(v.Interface())
493 if err != nil {
494 return err
495 }
496 needToQuote := string(b[0]) != `"` && (v.Kind() == reflect.Int64 || v.Kind() == reflect.Uint64)
497 if needToQuote {
498 out.write(`"`)
499 }
500 out.write(string(b))
501 if needToQuote {
502 out.write(`"`)
503 }
504 return out.err
505}
506
Nikki VonHollen99511272016-03-10 21:13:00 +1100507// UnmarshalNext unmarshals the next protocol buffer from a JSON object stream.
508// This function is lenient and will decode any options permutations of the
509// related Marshaler.
510func UnmarshalNext(dec *json.Decoder, pb proto.Message) error {
511 inputValue := json.RawMessage{}
512 if err := dec.Decode(&inputValue); err != nil {
513 return err
514 }
David Symondsf0a097d2016-04-13 14:01:00 +1000515 return unmarshalValue(reflect.ValueOf(pb).Elem(), inputValue, nil)
Nikki VonHollen99511272016-03-10 21:13:00 +1100516}
517
Buck Clay67cbcad2015-07-01 11:17:11 +1000518// Unmarshal unmarshals a JSON object stream into a protocol
519// buffer. This function is lenient and will decode any options
David Symonds21f81362015-08-17 11:59:00 +1000520// permutations of the related Marshaler.
Buck Clay67cbcad2015-07-01 11:17:11 +1000521func Unmarshal(r io.Reader, pb proto.Message) error {
Nikki VonHollen99511272016-03-10 21:13:00 +1100522 dec := json.NewDecoder(r)
523 return UnmarshalNext(dec, pb)
Buck Clay67cbcad2015-07-01 11:17:11 +1000524}
525
526// UnmarshalString will populate the fields of a protocol buffer based
527// on a JSON string. This function is lenient and will decode any options
David Symonds21f81362015-08-17 11:59:00 +1000528// permutations of the related Marshaler.
Buck Clay67cbcad2015-07-01 11:17:11 +1000529func UnmarshalString(str string, pb proto.Message) error {
David Symonds5d7f79b2015-10-19 11:37:00 +1100530 return Unmarshal(strings.NewReader(str), pb)
Buck Clay67cbcad2015-07-01 11:17:11 +1000531}
532
533// unmarshalValue converts/copies a value into the target.
David Symondsf0a097d2016-04-13 14:01:00 +1000534// prop may be nil.
535func unmarshalValue(target reflect.Value, inputValue json.RawMessage, prop *proto.Properties) error {
Buck Clay67cbcad2015-07-01 11:17:11 +1000536 targetType := target.Type()
537
538 // Allocate memory for pointer fields.
539 if targetType.Kind() == reflect.Ptr {
540 target.Set(reflect.New(targetType.Elem()))
David Symondsf0a097d2016-04-13 14:01:00 +1000541 return unmarshalValue(target.Elem(), inputValue, prop)
Buck Clay67cbcad2015-07-01 11:17:11 +1000542 }
543
David Symonds553c7642016-02-23 14:14:00 +1100544 // Handle well-known types.
545 type wkt interface {
546 XXX_WellKnownType() string
547 }
548 if wkt, ok := target.Addr().Interface().(wkt); ok {
549 switch wkt.XXX_WellKnownType() {
David Symondsc6184d32016-02-25 11:12:00 +1100550 case "DoubleValue", "FloatValue", "Int64Value", "UInt64Value",
551 "Int32Value", "UInt32Value", "BoolValue", "StringValue", "BytesValue":
552 // "Wrappers use the same representation in JSON
553 // as the wrapped primitive type, except that null is allowed."
554 // encoding/json will turn JSON `null` into Go `nil`,
555 // so we don't have to do any extra work.
David Symondsf0a097d2016-04-13 14:01:00 +1000556 return unmarshalValue(target.Field(0), inputValue, prop)
David Symondsbf531ff2016-04-20 14:40:00 +1000557 case "Any":
558 return fmt.Errorf("unmarshaling Any not supported yet")
David Symonds553c7642016-02-23 14:14:00 +1100559 case "Duration":
560 unq, err := strconv.Unquote(string(inputValue))
561 if err != nil {
562 return err
563 }
564 d, err := time.ParseDuration(unq)
565 if err != nil {
566 return fmt.Errorf("bad Duration: %v", err)
567 }
568 ns := d.Nanoseconds()
569 s := ns / 1e9
570 ns %= 1e9
571 target.Field(0).SetInt(s)
572 target.Field(1).SetInt(ns)
573 return nil
574 case "Timestamp":
575 unq, err := strconv.Unquote(string(inputValue))
576 if err != nil {
577 return err
578 }
579 t, err := time.Parse(time.RFC3339Nano, unq)
580 if err != nil {
581 return fmt.Errorf("bad Timestamp: %v", err)
582 }
583 ns := t.UnixNano()
584 s := ns / 1e9
585 ns %= 1e9
586 target.Field(0).SetInt(s)
587 target.Field(1).SetInt(ns)
588 return nil
589 }
590 }
591
David Symondsf0a097d2016-04-13 14:01:00 +1000592 // Handle enums, which have an underlying type of int32,
593 // and may appear as strings.
594 // The case of an enum appearing as a number is handled
595 // at the bottom of this function.
596 if inputValue[0] == '"' && prop != nil && prop.Enum != "" {
597 vmap := proto.EnumValueMap(prop.Enum)
598 // Don't need to do unquoting; valid enum names
599 // are from a limited character set.
600 s := inputValue[1 : len(inputValue)-1]
601 n, ok := vmap[string(s)]
602 if !ok {
603 return fmt.Errorf("unknown value %q for enum %s", s, prop.Enum)
604 }
605 if target.Kind() == reflect.Ptr { // proto2
606 target.Set(reflect.New(targetType.Elem()))
607 target = target.Elem()
608 }
609 target.SetInt(int64(n))
610 return nil
611 }
612
Buck Clay67cbcad2015-07-01 11:17:11 +1000613 // Handle nested messages.
614 if targetType.Kind() == reflect.Struct {
615 var jsonFields map[string]json.RawMessage
616 if err := json.Unmarshal(inputValue, &jsonFields); err != nil {
617 return err
618 }
619
David Symonds62e43642016-03-17 12:31:00 +1100620 consumeField := func(prop *proto.Properties) (json.RawMessage, bool) {
621 // Be liberal in what names we accept; both orig_name and camelName are okay.
622 fieldNames := acceptedJSONFieldNames(prop)
623
624 vOrig, okOrig := jsonFields[fieldNames.orig]
625 vCamel, okCamel := jsonFields[fieldNames.camel]
626 if !okOrig && !okCamel {
627 return nil, false
628 }
629 // If, for some reason, both are present in the data, favour the camelName.
630 var raw json.RawMessage
631 if okOrig {
632 raw = vOrig
633 delete(jsonFields, fieldNames.orig)
634 }
635 if okCamel {
636 raw = vCamel
637 delete(jsonFields, fieldNames.camel)
638 }
639 return raw, true
640 }
641
David Symonds5d7f79b2015-10-19 11:37:00 +1100642 sprops := proto.GetProperties(targetType)
Buck Clay67cbcad2015-07-01 11:17:11 +1000643 for i := 0; i < target.NumField(); i++ {
David Symonds31db5692015-08-10 12:45:00 +1000644 ft := target.Type().Field(i)
645 if strings.HasPrefix(ft.Name, "XXX_") {
Buck Clay67cbcad2015-07-01 11:17:11 +1000646 continue
647 }
648
David Symonds62e43642016-03-17 12:31:00 +1100649 valueForField, ok := consumeField(sprops.Prop[i])
650 if !ok {
David Symonds5d7f79b2015-10-19 11:37:00 +1100651 continue
652 }
David Symonds5d7f79b2015-10-19 11:37:00 +1100653
David Symondsf0a097d2016-04-13 14:01:00 +1000654 if err := unmarshalValue(target.Field(i), valueForField, sprops.Prop[i]); err != nil {
David Symonds5d7f79b2015-10-19 11:37:00 +1100655 return err
Buck Clay67cbcad2015-07-01 11:17:11 +1000656 }
657 }
David Symonds59b73b32015-08-24 13:22:02 +1000658 // Check for any oneof fields.
David Symonds62e43642016-03-17 12:31:00 +1100659 if len(jsonFields) > 0 {
660 for _, oop := range sprops.OneofTypes {
661 raw, ok := consumeField(oop.Prop)
662 if !ok {
663 continue
664 }
David Symonds1baed092015-08-25 15:42:00 +1000665 nv := reflect.New(oop.Type.Elem())
666 target.Field(oop.Field).Set(nv)
David Symondsf0a097d2016-04-13 14:01:00 +1000667 if err := unmarshalValue(nv.Elem().Field(0), raw, oop.Prop); err != nil {
David Symonds59b73b32015-08-24 13:22:02 +1000668 return err
669 }
David Symonds59b73b32015-08-24 13:22:02 +1000670 }
671 }
David Symonds3fe63ce2015-08-07 15:00:00 +1000672 if len(jsonFields) > 0 {
673 // Pick any field to be the scapegoat.
674 var f string
675 for fname := range jsonFields {
676 f = fname
677 break
678 }
679 return fmt.Errorf("unknown field %q in %v", f, targetType)
680 }
Buck Clay67cbcad2015-07-01 11:17:11 +1000681 return nil
682 }
683
684 // Handle arrays (which aren't encoded bytes)
685 if targetType != byteArrayType && targetType.Kind() == reflect.Slice {
686 var slc []json.RawMessage
687 if err := json.Unmarshal(inputValue, &slc); err != nil {
688 return err
689 }
690 len := len(slc)
691 target.Set(reflect.MakeSlice(targetType, len, len))
692 for i := 0; i < len; i++ {
David Symondsf0a097d2016-04-13 14:01:00 +1000693 if err := unmarshalValue(target.Index(i), slc[i], prop); err != nil {
Buck Clay67cbcad2015-07-01 11:17:11 +1000694 return err
695 }
696 }
697 return nil
698 }
699
700 // Handle maps (whose keys are always strings)
701 if targetType.Kind() == reflect.Map {
702 var mp map[string]json.RawMessage
703 if err := json.Unmarshal(inputValue, &mp); err != nil {
704 return err
705 }
706 target.Set(reflect.MakeMap(targetType))
David Symondsf0a097d2016-04-13 14:01:00 +1000707 var keyprop, valprop *proto.Properties
708 if prop != nil {
709 // These could still be nil if the protobuf metadata is broken somehow.
710 // TODO: This won't work because the fields are unexported.
711 // We should probably just reparse them.
712 //keyprop, valprop = prop.mkeyprop, prop.mvalprop
713 }
Buck Clay67cbcad2015-07-01 11:17:11 +1000714 for ks, raw := range mp {
715 // Unmarshal map key. The core json library already decoded the key into a
716 // string, so we handle that specially. Other types were quoted post-serialization.
717 var k reflect.Value
718 if targetType.Key().Kind() == reflect.String {
719 k = reflect.ValueOf(ks)
720 } else {
721 k = reflect.New(targetType.Key()).Elem()
David Symondsf0a097d2016-04-13 14:01:00 +1000722 if err := unmarshalValue(k, json.RawMessage(ks), keyprop); err != nil {
Buck Clay67cbcad2015-07-01 11:17:11 +1000723 return err
724 }
725 }
726
727 // Unmarshal map value.
728 v := reflect.New(targetType.Elem()).Elem()
David Symondsf0a097d2016-04-13 14:01:00 +1000729 if err := unmarshalValue(v, raw, valprop); err != nil {
Buck Clay67cbcad2015-07-01 11:17:11 +1000730 return err
731 }
732 target.SetMapIndex(k, v)
733 }
734 return nil
735 }
736
737 // 64-bit integers can be encoded as strings. In this case we drop
738 // the quotes and proceed as normal.
739 isNum := targetType.Kind() == reflect.Int64 || targetType.Kind() == reflect.Uint64
740 if isNum && strings.HasPrefix(string(inputValue), `"`) {
741 inputValue = inputValue[1 : len(inputValue)-1]
742 }
743
744 // Use the encoding/json for parsing other value types.
745 return json.Unmarshal(inputValue, target.Addr().Interface())
746}
747
David Symonds001690d2016-02-10 14:04:11 +1100748// jsonProperties returns parsed proto.Properties for the field and corrects JSONName attribute.
749func jsonProperties(f reflect.StructField, origName bool) *proto.Properties {
David Symonds31db5692015-08-10 12:45:00 +1000750 var prop proto.Properties
751 prop.Init(f.Type, f.Name, f.Tag.Get("protobuf"), &f)
David Symonds001690d2016-02-10 14:04:11 +1100752 if origName || prop.JSONName == "" {
753 prop.JSONName = prop.OrigName
754 }
Juraj Stachof9dd6932015-11-03 18:47:00 +1100755 return &prop
756}
757
David Symonds001690d2016-02-10 14:04:11 +1100758type fieldNames struct {
759 orig, camel string
760}
761
David Symonds62e43642016-03-17 12:31:00 +1100762func acceptedJSONFieldNames(prop *proto.Properties) fieldNames {
David Symonds001690d2016-02-10 14:04:11 +1100763 opts := fieldNames{orig: prop.OrigName, camel: prop.OrigName}
764 if prop.JSONName != "" {
765 opts.camel = prop.JSONName
766 }
767 return opts
768}
769
Juraj Stachof9dd6932015-11-03 18:47:00 +1100770// extendableProto is an interface implemented by any protocol buffer that may be extended.
771type extendableProto interface {
772 proto.Message
773 ExtensionRangeArray() []proto.ExtensionRange
774 ExtensionMap() map[int32]proto.Extension
Buck Clay67cbcad2015-07-01 11:17:11 +1000775}
776
777// Writer wrapper inspired by https://blog.golang.org/errors-are-values
778type errWriter struct {
779 writer io.Writer
780 err error
781}
782
783func (w *errWriter) write(str string) {
784 if w.err != nil {
785 return
786 }
787 _, w.err = w.writer.Write([]byte(str))
788}
789
790// Map fields may have key types of non-float scalars, strings and enums.
791// The easiest way to sort them in some deterministic order is to use fmt.
792// If this turns out to be inefficient we can always consider other options,
793// such as doing a Schwartzian transform.
794type mapKeys []reflect.Value
795
796func (s mapKeys) Len() int { return len(s) }
797func (s mapKeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
798func (s mapKeys) Less(i, j int) bool {
799 return fmt.Sprint(s[i].Interface()) < fmt.Sprint(s[j].Interface())
800}