blob: e9438a93f331c3b166a0282c84bdad43d31b9afe [file] [log] [blame]
khenaidoof3333552021-12-15 16:52:31 -05001// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package jsonpb
6
7import (
8 "encoding/json"
9 "errors"
10 "fmt"
11 "io"
12 "math"
13 "reflect"
14 "sort"
15 "strconv"
16 "strings"
17 "time"
18
19 "github.com/golang/protobuf/proto"
20 "google.golang.org/protobuf/encoding/protojson"
21 protoV2 "google.golang.org/protobuf/proto"
22 "google.golang.org/protobuf/reflect/protoreflect"
23 "google.golang.org/protobuf/reflect/protoregistry"
24)
25
26const wrapJSONMarshalV2 = false
27
28// Marshaler is a configurable object for marshaling protocol buffer messages
29// to the specified JSON representation.
30type Marshaler struct {
31 // OrigName specifies whether to use the original protobuf name for fields.
32 OrigName bool
33
34 // EnumsAsInts specifies whether to render enum values as integers,
35 // as opposed to string values.
36 EnumsAsInts bool
37
38 // EmitDefaults specifies whether to render fields with zero values.
39 EmitDefaults bool
40
41 // Indent controls whether the output is compact or not.
42 // If empty, the output is compact JSON. Otherwise, every JSON object
43 // entry and JSON array value will be on its own line.
44 // Each line will be preceded by repeated copies of Indent, where the
45 // number of copies is the current indentation depth.
46 Indent string
47
48 // AnyResolver is used to resolve the google.protobuf.Any well-known type.
49 // If unset, the global registry is used by default.
50 AnyResolver AnyResolver
51}
52
53// JSONPBMarshaler is implemented by protobuf messages that customize the
54// way they are marshaled to JSON. Messages that implement this should also
55// implement JSONPBUnmarshaler so that the custom format can be parsed.
56//
57// The JSON marshaling must follow the proto to JSON specification:
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +053058//
khenaidoof3333552021-12-15 16:52:31 -050059// https://developers.google.com/protocol-buffers/docs/proto3#json
60//
61// Deprecated: Custom types should implement protobuf reflection instead.
62type JSONPBMarshaler interface {
63 MarshalJSONPB(*Marshaler) ([]byte, error)
64}
65
66// Marshal serializes a protobuf message as JSON into w.
67func (jm *Marshaler) Marshal(w io.Writer, m proto.Message) error {
68 b, err := jm.marshal(m)
69 if len(b) > 0 {
70 if _, err := w.Write(b); err != nil {
71 return err
72 }
73 }
74 return err
75}
76
77// MarshalToString serializes a protobuf message as JSON in string form.
78func (jm *Marshaler) MarshalToString(m proto.Message) (string, error) {
79 b, err := jm.marshal(m)
80 if err != nil {
81 return "", err
82 }
83 return string(b), nil
84}
85
86func (jm *Marshaler) marshal(m proto.Message) ([]byte, error) {
87 v := reflect.ValueOf(m)
88 if m == nil || (v.Kind() == reflect.Ptr && v.IsNil()) {
89 return nil, errors.New("Marshal called with nil")
90 }
91
92 // Check for custom marshalers first since they may not properly
93 // implement protobuf reflection that the logic below relies on.
94 if jsm, ok := m.(JSONPBMarshaler); ok {
95 return jsm.MarshalJSONPB(jm)
96 }
97
98 if wrapJSONMarshalV2 {
99 opts := protojson.MarshalOptions{
100 UseProtoNames: jm.OrigName,
101 UseEnumNumbers: jm.EnumsAsInts,
102 EmitUnpopulated: jm.EmitDefaults,
103 Indent: jm.Indent,
104 }
105 if jm.AnyResolver != nil {
106 opts.Resolver = anyResolver{jm.AnyResolver}
107 }
108 return opts.Marshal(proto.MessageReflect(m).Interface())
109 } else {
110 // Check for unpopulated required fields first.
111 m2 := proto.MessageReflect(m)
112 if err := protoV2.CheckInitialized(m2.Interface()); err != nil {
113 return nil, err
114 }
115
116 w := jsonWriter{Marshaler: jm}
117 err := w.marshalMessage(m2, "", "")
118 return w.buf, err
119 }
120}
121
122type jsonWriter struct {
123 *Marshaler
124 buf []byte
125}
126
127func (w *jsonWriter) write(s string) {
128 w.buf = append(w.buf, s...)
129}
130
131func (w *jsonWriter) marshalMessage(m protoreflect.Message, indent, typeURL string) error {
132 if jsm, ok := proto.MessageV1(m.Interface()).(JSONPBMarshaler); ok {
133 b, err := jsm.MarshalJSONPB(w.Marshaler)
134 if err != nil {
135 return err
136 }
137 if typeURL != "" {
138 // we are marshaling this object to an Any type
139 var js map[string]*json.RawMessage
140 if err = json.Unmarshal(b, &js); err != nil {
141 return fmt.Errorf("type %T produced invalid JSON: %v", m.Interface(), err)
142 }
143 turl, err := json.Marshal(typeURL)
144 if err != nil {
145 return fmt.Errorf("failed to marshal type URL %q to JSON: %v", typeURL, err)
146 }
147 js["@type"] = (*json.RawMessage)(&turl)
148 if b, err = json.Marshal(js); err != nil {
149 return err
150 }
151 }
152 w.write(string(b))
153 return nil
154 }
155
156 md := m.Descriptor()
157 fds := md.Fields()
158
159 // Handle well-known types.
160 const secondInNanos = int64(time.Second / time.Nanosecond)
161 switch wellKnownType(md.FullName()) {
162 case "Any":
163 return w.marshalAny(m, indent)
164 case "BoolValue", "BytesValue", "StringValue",
165 "Int32Value", "UInt32Value", "FloatValue",
166 "Int64Value", "UInt64Value", "DoubleValue":
167 fd := fds.ByNumber(1)
168 return w.marshalValue(fd, m.Get(fd), indent)
169 case "Duration":
170 const maxSecondsInDuration = 315576000000
171 // "Generated output always contains 0, 3, 6, or 9 fractional digits,
172 // depending on required precision."
173 s := m.Get(fds.ByNumber(1)).Int()
174 ns := m.Get(fds.ByNumber(2)).Int()
175 if s < -maxSecondsInDuration || s > maxSecondsInDuration {
176 return fmt.Errorf("seconds out of range %v", s)
177 }
178 if ns <= -secondInNanos || ns >= secondInNanos {
179 return fmt.Errorf("ns out of range (%v, %v)", -secondInNanos, secondInNanos)
180 }
181 if (s > 0 && ns < 0) || (s < 0 && ns > 0) {
182 return errors.New("signs of seconds and nanos do not match")
183 }
184 var sign string
185 if s < 0 || ns < 0 {
186 sign, s, ns = "-", -1*s, -1*ns
187 }
188 x := fmt.Sprintf("%s%d.%09d", sign, s, ns)
189 x = strings.TrimSuffix(x, "000")
190 x = strings.TrimSuffix(x, "000")
191 x = strings.TrimSuffix(x, ".000")
192 w.write(fmt.Sprintf(`"%vs"`, x))
193 return nil
194 case "Timestamp":
195 // "RFC 3339, where generated output will always be Z-normalized
196 // and uses 0, 3, 6 or 9 fractional digits."
197 s := m.Get(fds.ByNumber(1)).Int()
198 ns := m.Get(fds.ByNumber(2)).Int()
199 if ns < 0 || ns >= secondInNanos {
200 return fmt.Errorf("ns out of range [0, %v)", secondInNanos)
201 }
202 t := time.Unix(s, ns).UTC()
203 // time.RFC3339Nano isn't exactly right (we need to get 3/6/9 fractional digits).
204 x := t.Format("2006-01-02T15:04:05.000000000")
205 x = strings.TrimSuffix(x, "000")
206 x = strings.TrimSuffix(x, "000")
207 x = strings.TrimSuffix(x, ".000")
208 w.write(fmt.Sprintf(`"%vZ"`, x))
209 return nil
210 case "Value":
211 // JSON value; which is a null, number, string, bool, object, or array.
212 od := md.Oneofs().Get(0)
213 fd := m.WhichOneof(od)
214 if fd == nil {
215 return errors.New("nil Value")
216 }
217 return w.marshalValue(fd, m.Get(fd), indent)
218 case "Struct", "ListValue":
219 // JSON object or array.
220 fd := fds.ByNumber(1)
221 return w.marshalValue(fd, m.Get(fd), indent)
222 }
223
224 w.write("{")
225 if w.Indent != "" {
226 w.write("\n")
227 }
228
229 firstField := true
230 if typeURL != "" {
231 if err := w.marshalTypeURL(indent, typeURL); err != nil {
232 return err
233 }
234 firstField = false
235 }
236
237 for i := 0; i < fds.Len(); {
238 fd := fds.Get(i)
239 if od := fd.ContainingOneof(); od != nil {
240 fd = m.WhichOneof(od)
241 i += od.Fields().Len()
242 if fd == nil {
243 continue
244 }
245 } else {
246 i++
247 }
248
249 v := m.Get(fd)
250
251 if !m.Has(fd) {
252 if !w.EmitDefaults || fd.ContainingOneof() != nil {
253 continue
254 }
255 if fd.Cardinality() != protoreflect.Repeated && (fd.Message() != nil || fd.Syntax() == protoreflect.Proto2) {
256 v = protoreflect.Value{} // use "null" for singular messages or proto2 scalars
257 }
258 }
259
260 if !firstField {
261 w.writeComma()
262 }
263 if err := w.marshalField(fd, v, indent); err != nil {
264 return err
265 }
266 firstField = false
267 }
268
269 // Handle proto2 extensions.
270 if md.ExtensionRanges().Len() > 0 {
271 // Collect a sorted list of all extension descriptor and values.
272 type ext struct {
273 desc protoreflect.FieldDescriptor
274 val protoreflect.Value
275 }
276 var exts []ext
277 m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
278 if fd.IsExtension() {
279 exts = append(exts, ext{fd, v})
280 }
281 return true
282 })
283 sort.Slice(exts, func(i, j int) bool {
284 return exts[i].desc.Number() < exts[j].desc.Number()
285 })
286
287 for _, ext := range exts {
288 if !firstField {
289 w.writeComma()
290 }
291 if err := w.marshalField(ext.desc, ext.val, indent); err != nil {
292 return err
293 }
294 firstField = false
295 }
296 }
297
298 if w.Indent != "" {
299 w.write("\n")
300 w.write(indent)
301 }
302 w.write("}")
303 return nil
304}
305
306func (w *jsonWriter) writeComma() {
307 if w.Indent != "" {
308 w.write(",\n")
309 } else {
310 w.write(",")
311 }
312}
313
314func (w *jsonWriter) marshalAny(m protoreflect.Message, indent string) error {
315 // "If the Any contains a value that has a special JSON mapping,
316 // it will be converted as follows: {"@type": xxx, "value": yyy}.
317 // Otherwise, the value will be converted into a JSON object,
318 // and the "@type" field will be inserted to indicate the actual data type."
319 md := m.Descriptor()
320 typeURL := m.Get(md.Fields().ByNumber(1)).String()
321 rawVal := m.Get(md.Fields().ByNumber(2)).Bytes()
322
323 var m2 protoreflect.Message
324 if w.AnyResolver != nil {
325 mi, err := w.AnyResolver.Resolve(typeURL)
326 if err != nil {
327 return err
328 }
329 m2 = proto.MessageReflect(mi)
330 } else {
331 mt, err := protoregistry.GlobalTypes.FindMessageByURL(typeURL)
332 if err != nil {
333 return err
334 }
335 m2 = mt.New()
336 }
337
338 if err := protoV2.Unmarshal(rawVal, m2.Interface()); err != nil {
339 return err
340 }
341
342 if wellKnownType(m2.Descriptor().FullName()) == "" {
343 return w.marshalMessage(m2, indent, typeURL)
344 }
345
346 w.write("{")
347 if w.Indent != "" {
348 w.write("\n")
349 }
350 if err := w.marshalTypeURL(indent, typeURL); err != nil {
351 return err
352 }
353 w.writeComma()
354 if w.Indent != "" {
355 w.write(indent)
356 w.write(w.Indent)
357 w.write(`"value": `)
358 } else {
359 w.write(`"value":`)
360 }
361 if err := w.marshalMessage(m2, indent+w.Indent, ""); err != nil {
362 return err
363 }
364 if w.Indent != "" {
365 w.write("\n")
366 w.write(indent)
367 }
368 w.write("}")
369 return nil
370}
371
372func (w *jsonWriter) marshalTypeURL(indent, typeURL string) error {
373 if w.Indent != "" {
374 w.write(indent)
375 w.write(w.Indent)
376 }
377 w.write(`"@type":`)
378 if w.Indent != "" {
379 w.write(" ")
380 }
381 b, err := json.Marshal(typeURL)
382 if err != nil {
383 return err
384 }
385 w.write(string(b))
386 return nil
387}
388
389// marshalField writes field description and value to the Writer.
390func (w *jsonWriter) marshalField(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error {
391 if w.Indent != "" {
392 w.write(indent)
393 w.write(w.Indent)
394 }
395 w.write(`"`)
396 switch {
397 case fd.IsExtension():
398 // For message set, use the fname of the message as the extension name.
399 name := string(fd.FullName())
400 if isMessageSet(fd.ContainingMessage()) {
401 name = strings.TrimSuffix(name, ".message_set_extension")
402 }
403
404 w.write("[" + name + "]")
405 case w.OrigName:
406 name := string(fd.Name())
407 if fd.Kind() == protoreflect.GroupKind {
408 name = string(fd.Message().Name())
409 }
410 w.write(name)
411 default:
412 w.write(string(fd.JSONName()))
413 }
414 w.write(`":`)
415 if w.Indent != "" {
416 w.write(" ")
417 }
418 return w.marshalValue(fd, v, indent)
419}
420
421func (w *jsonWriter) marshalValue(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error {
422 switch {
423 case fd.IsList():
424 w.write("[")
425 comma := ""
426 lv := v.List()
427 for i := 0; i < lv.Len(); i++ {
428 w.write(comma)
429 if w.Indent != "" {
430 w.write("\n")
431 w.write(indent)
432 w.write(w.Indent)
433 w.write(w.Indent)
434 }
435 if err := w.marshalSingularValue(fd, lv.Get(i), indent+w.Indent); err != nil {
436 return err
437 }
438 comma = ","
439 }
440 if w.Indent != "" {
441 w.write("\n")
442 w.write(indent)
443 w.write(w.Indent)
444 }
445 w.write("]")
446 return nil
447 case fd.IsMap():
448 kfd := fd.MapKey()
449 vfd := fd.MapValue()
450 mv := v.Map()
451
452 // Collect a sorted list of all map keys and values.
453 type entry struct{ key, val protoreflect.Value }
454 var entries []entry
455 mv.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
456 entries = append(entries, entry{k.Value(), v})
457 return true
458 })
459 sort.Slice(entries, func(i, j int) bool {
460 switch kfd.Kind() {
461 case protoreflect.BoolKind:
462 return !entries[i].key.Bool() && entries[j].key.Bool()
463 case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
464 return entries[i].key.Int() < entries[j].key.Int()
465 case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
466 return entries[i].key.Uint() < entries[j].key.Uint()
467 case protoreflect.StringKind:
468 return entries[i].key.String() < entries[j].key.String()
469 default:
470 panic("invalid kind")
471 }
472 })
473
474 w.write(`{`)
475 comma := ""
476 for _, entry := range entries {
477 w.write(comma)
478 if w.Indent != "" {
479 w.write("\n")
480 w.write(indent)
481 w.write(w.Indent)
482 w.write(w.Indent)
483 }
484
485 s := fmt.Sprint(entry.key.Interface())
486 b, err := json.Marshal(s)
487 if err != nil {
488 return err
489 }
490 w.write(string(b))
491
492 w.write(`:`)
493 if w.Indent != "" {
494 w.write(` `)
495 }
496
497 if err := w.marshalSingularValue(vfd, entry.val, indent+w.Indent); err != nil {
498 return err
499 }
500 comma = ","
501 }
502 if w.Indent != "" {
503 w.write("\n")
504 w.write(indent)
505 w.write(w.Indent)
506 }
507 w.write(`}`)
508 return nil
509 default:
510 return w.marshalSingularValue(fd, v, indent)
511 }
512}
513
514func (w *jsonWriter) marshalSingularValue(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error {
515 switch {
516 case !v.IsValid():
517 w.write("null")
518 return nil
519 case fd.Message() != nil:
520 return w.marshalMessage(v.Message(), indent+w.Indent, "")
521 case fd.Enum() != nil:
522 if fd.Enum().FullName() == "google.protobuf.NullValue" {
523 w.write("null")
524 return nil
525 }
526
527 vd := fd.Enum().Values().ByNumber(v.Enum())
528 if vd == nil || w.EnumsAsInts {
529 w.write(strconv.Itoa(int(v.Enum())))
530 } else {
531 w.write(`"` + string(vd.Name()) + `"`)
532 }
533 return nil
534 default:
535 switch v.Interface().(type) {
536 case float32, float64:
537 switch {
538 case math.IsInf(v.Float(), +1):
539 w.write(`"Infinity"`)
540 return nil
541 case math.IsInf(v.Float(), -1):
542 w.write(`"-Infinity"`)
543 return nil
544 case math.IsNaN(v.Float()):
545 w.write(`"NaN"`)
546 return nil
547 }
548 case int64, uint64:
549 w.write(fmt.Sprintf(`"%d"`, v.Interface()))
550 return nil
551 }
552
553 b, err := json.Marshal(v.Interface())
554 if err != nil {
555 return err
556 }
557 w.write(string(b))
558 return nil
559 }
560}