1// Copyright 2019 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 protojson
6
7import (
8 "encoding/base64"
9 "fmt"
10
11 "google.golang.org/protobuf/internal/encoding/json"
12 "google.golang.org/protobuf/internal/encoding/messageset"
13 "google.golang.org/protobuf/internal/errors"
14 "google.golang.org/protobuf/internal/filedesc"
15 "google.golang.org/protobuf/internal/flags"
16 "google.golang.org/protobuf/internal/genid"
17 "google.golang.org/protobuf/internal/order"
18 "google.golang.org/protobuf/internal/pragma"
19 "google.golang.org/protobuf/proto"
20 "google.golang.org/protobuf/reflect/protoreflect"
21 "google.golang.org/protobuf/reflect/protoregistry"
22)
23
24const defaultIndent = " "
25
26// Format formats the message as a multiline string.
27// This function is only intended for human consumption and ignores errors.
28// Do not depend on the output being stable. Its output will change across
29// different builds of your program, even when using the same version of the
30// protobuf module.
31func Format(m proto.Message) string {
32 return MarshalOptions{Multiline: true}.Format(m)
33}
34
35// Marshal writes the given [proto.Message] in JSON format using default options.
36// Do not depend on the output being stable. Its output will change across
37// different builds of your program, even when using the same version of the
38// protobuf module.
39func Marshal(m proto.Message) ([]byte, error) {
40 return MarshalOptions{}.Marshal(m)
41}
42
43// MarshalOptions is a configurable JSON format marshaler.
44type MarshalOptions struct {
45 pragma.NoUnkeyedLiterals
46
47 // Multiline specifies whether the marshaler should format the output in
48 // indented-form with every textual element on a new line.
49 // If Indent is an empty string, then an arbitrary indent is chosen.
50 Multiline bool
51
52 // Indent specifies the set of indentation characters to use in a multiline
53 // formatted output such that every entry is preceded by Indent and
54 // terminated by a newline. If non-empty, then Multiline is treated as true.
55 // Indent can only be composed of space or tab characters.
56 Indent string
57
58 // AllowPartial allows messages that have missing required fields to marshal
59 // without returning an error. If AllowPartial is false (the default),
60 // Marshal will return error if there are any missing required fields.
61 AllowPartial bool
62
63 // UseProtoNames uses proto field name instead of lowerCamelCase name in JSON
64 // field names.
65 UseProtoNames bool
66
67 // UseEnumNumbers emits enum values as numbers.
68 UseEnumNumbers bool
69
70 // EmitUnpopulated specifies whether to emit unpopulated fields. It does not
71 // emit unpopulated oneof fields or unpopulated extension fields.
72 // The JSON value emitted for unpopulated fields are as follows:
73 // โโโโโโโโโคโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
74 // โ JSON โ Protobuf field โ
75 // โ โโโโโโโโชโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฃ
76 // โ false โ proto3 boolean fields โ
77 // โ 0 โ proto3 numeric fields โ
78 // โ "" โ proto3 string/bytes fields โ
79 // โ null โ proto2 scalar fields โ
80 // โ null โ message fields โ
81 // โ [] โ list fields โ
82 // โ {} โ map fields โ
83 // โโโโโโโโโงโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
84 EmitUnpopulated bool
85
86 // EmitDefaultValues specifies whether to emit default-valued primitive fields,
87 // empty lists, and empty maps. The fields affected are as follows:
88 // โโโโโโโโโคโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
89 // โ JSON โ Protobuf field โ
90 // โ โโโโโโโโชโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฃ
91 // โ false โ non-optional scalar boolean fields โ
92 // โ 0 โ non-optional scalar numeric fields โ
93 // โ "" โ non-optional scalar string/byte fields โ
94 // โ [] โ empty repeated fields โ
95 // โ {} โ empty map fields โ
96 // โโโโโโโโโงโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
97 //
98 // Behaves similarly to EmitUnpopulated, but does not emit "null"-value fields,
99 // i.e. presence-sensing fields that are omitted will remain omitted to preserve
100 // presence-sensing.
101 // EmitUnpopulated takes precedence over EmitDefaultValues since the former generates
102 // a strict superset of the latter.
103 EmitDefaultValues bool
104
105 // Resolver is used for looking up types when expanding google.protobuf.Any
106 // messages. If nil, this defaults to using protoregistry.GlobalTypes.
107 Resolver interface {
108 protoregistry.ExtensionTypeResolver
109 protoregistry.MessageTypeResolver
110 }
111}
112
113// Format formats the message as a string.
114// This method is only intended for human consumption and ignores errors.
115// Do not depend on the output being stable. Its output will change across
116// different builds of your program, even when using the same version of the
117// protobuf module.
118func (o MarshalOptions) Format(m proto.Message) string {
119 if m == nil || !m.ProtoReflect().IsValid() {
120 return "<nil>" // invalid syntax, but okay since this is for debugging
121 }
122 o.AllowPartial = true
123 b, _ := o.Marshal(m)
124 return string(b)
125}
126
127// Marshal marshals the given [proto.Message] in the JSON format using options in
128// Do not depend on the output being stable. Its output will change across
129// different builds of your program, even when using the same version of the
130// protobuf module.
131func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) {
132 return o.marshal(nil, m)
133}
134
135// MarshalAppend appends the JSON format encoding of m to b,
136// returning the result.
137func (o MarshalOptions) MarshalAppend(b []byte, m proto.Message) ([]byte, error) {
138 return o.marshal(b, m)
139}
140
141// marshal is a centralized function that all marshal operations go through.
142// For profiling purposes, avoid changing the name of this function or
143// introducing other code paths for marshal that do not go through this.
144func (o MarshalOptions) marshal(b []byte, m proto.Message) ([]byte, error) {
145 if o.Multiline && o.Indent == "" {
146 o.Indent = defaultIndent
147 }
148 if o.Resolver == nil {
149 o.Resolver = protoregistry.GlobalTypes
150 }
151
152 internalEnc, err := json.NewEncoder(b, o.Indent)
153 if err != nil {
154 return nil, err
155 }
156
157 // Treat nil message interface as an empty message,
158 // in which case the output in an empty JSON object.
159 if m == nil {
160 return append(b, '{', '}'), nil
161 }
162
163 enc := encoder{internalEnc, o}
164 if err := enc.marshalMessage(m.ProtoReflect(), ""); err != nil {
165 return nil, err
166 }
167 if o.AllowPartial {
168 return enc.Bytes(), nil
169 }
170 return enc.Bytes(), proto.CheckInitialized(m)
171}
172
173type encoder struct {
174 *json.Encoder
175 opts MarshalOptions
176}
177
178// typeFieldDesc is a synthetic field descriptor used for the "@type" field.
179var typeFieldDesc = func() protoreflect.FieldDescriptor {
180 var fd filedesc.Field
181 fd.L0.FullName = "@type"
182 fd.L0.Index = -1
183 fd.L1.Cardinality = protoreflect.Optional
184 fd.L1.Kind = protoreflect.StringKind
185 return &fd
186}()
187
188// typeURLFieldRanger wraps a protoreflect.Message and modifies its Range method
189// to additionally iterate over a synthetic field for the type URL.
190type typeURLFieldRanger struct {
191 order.FieldRanger
192 typeURL string
193}
194
195func (m typeURLFieldRanger) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {
196 if !f(typeFieldDesc, protoreflect.ValueOfString(m.typeURL)) {
197 return
198 }
199 m.FieldRanger.Range(f)
200}
201
202// unpopulatedFieldRanger wraps a protoreflect.Message and modifies its Range
203// method to additionally iterate over unpopulated fields.
204type unpopulatedFieldRanger struct {
205 protoreflect.Message
206
207 skipNull bool
208}
209
210func (m unpopulatedFieldRanger) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {
211 fds := m.Descriptor().Fields()
212 for i := 0; i < fds.Len(); i++ {
213 fd := fds.Get(i)
214 if m.Has(fd) || fd.ContainingOneof() != nil {
215 continue // ignore populated fields and fields within a oneofs
216 }
217
218 v := m.Get(fd)
219 if fd.HasPresence() {
220 if m.skipNull {
221 continue
222 }
223 v = protoreflect.Value{} // use invalid value to emit null
224 }
225 if !f(fd, v) {
226 return
227 }
228 }
229 m.Message.Range(f)
230}
231
232// marshalMessage marshals the fields in the given protoreflect.Message.
233// If the typeURL is non-empty, then a synthetic "@type" field is injected
234// containing the URL as the value.
235func (e encoder) marshalMessage(m protoreflect.Message, typeURL string) error {
236 if !flags.ProtoLegacy && messageset.IsMessageSet(m.Descriptor()) {
237 return errors.New("no support for proto1 MessageSets")
238 }
239
240 if marshal := wellKnownTypeMarshaler(m.Descriptor().FullName()); marshal != nil {
241 return marshal(e, m)
242 }
243
244 e.StartObject()
245 defer e.EndObject()
246
247 var fields order.FieldRanger = m
248 switch {
249 case e.opts.EmitUnpopulated:
250 fields = unpopulatedFieldRanger{Message: m, skipNull: false}
251 case e.opts.EmitDefaultValues:
252 fields = unpopulatedFieldRanger{Message: m, skipNull: true}
253 }
254 if typeURL != "" {
255 fields = typeURLFieldRanger{fields, typeURL}
256 }
257
258 var err error
259 order.RangeFields(fields, order.IndexNameFieldOrder, func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
260 name := fd.JSONName()
261 if e.opts.UseProtoNames {
262 name = fd.TextName()
263 }
264
265 if err = e.WriteName(name); err != nil {
266 return false
267 }
268 if err = e.marshalValue(v, fd); err != nil {
269 return false
270 }
271 return true
272 })
273 return err
274}
275
276// marshalValue marshals the given protoreflect.Value.
277func (e encoder) marshalValue(val protoreflect.Value, fd protoreflect.FieldDescriptor) error {
278 switch {
279 case fd.IsList():
280 return e.marshalList(val.List(), fd)
281 case fd.IsMap():
282 return e.marshalMap(val.Map(), fd)
283 default:
284 return e.marshalSingular(val, fd)
285 }
286}
287
288// marshalSingular marshals the given non-repeated field value. This includes
289// all scalar types, enums, messages, and groups.
290func (e encoder) marshalSingular(val protoreflect.Value, fd protoreflect.FieldDescriptor) error {
291 if !val.IsValid() {
292 e.WriteNull()
293 return nil
294 }
295
296 switch kind := fd.Kind(); kind {
297 case protoreflect.BoolKind:
298 e.WriteBool(val.Bool())
299
300 case protoreflect.StringKind:
301 if e.WriteString(val.String()) != nil {
302 return errors.InvalidUTF8(string(fd.FullName()))
303 }
304
305 case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
306 e.WriteInt(val.Int())
307
308 case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
309 e.WriteUint(val.Uint())
310
311 case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Uint64Kind,
312 protoreflect.Sfixed64Kind, protoreflect.Fixed64Kind:
313 // 64-bit integers are written out as JSON string.
314 e.WriteString(val.String())
315
316 case protoreflect.FloatKind:
317 // Encoder.WriteFloat handles the special numbers NaN and infinites.
318 e.WriteFloat(val.Float(), 32)
319
320 case protoreflect.DoubleKind:
321 // Encoder.WriteFloat handles the special numbers NaN and infinites.
322 e.WriteFloat(val.Float(), 64)
323
324 case protoreflect.BytesKind:
325 e.WriteString(base64.StdEncoding.EncodeToString(val.Bytes()))
326
327 case protoreflect.EnumKind:
328 if fd.Enum().FullName() == genid.NullValue_enum_fullname {
329 e.WriteNull()
330 } else {
331 desc := fd.Enum().Values().ByNumber(val.Enum())
332 if e.opts.UseEnumNumbers || desc == nil {
333 e.WriteInt(int64(val.Enum()))
334 } else {
335 e.WriteString(string(desc.Name()))
336 }
337 }
338
339 case protoreflect.MessageKind, protoreflect.GroupKind:
340 if err := e.marshalMessage(val.Message(), ""); err != nil {
341 return err
342 }
343
344 default:
345 panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind))
346 }
347 return nil
348}
349
350// marshalList marshals the given protoreflect.List.
351func (e encoder) marshalList(list protoreflect.List, fd protoreflect.FieldDescriptor) error {
352 e.StartArray()
353 defer e.EndArray()
354
355 for i := 0; i < list.Len(); i++ {
356 item := list.Get(i)
357 if err := e.marshalSingular(item, fd); err != nil {
358 return err
359 }
360 }
361 return nil
362}
363
364// marshalMap marshals given protoreflect.Map.
365func (e encoder) marshalMap(mmap protoreflect.Map, fd protoreflect.FieldDescriptor) error {
366 e.StartObject()
367 defer e.EndObject()
368
369 var err error
370 order.RangeEntries(mmap, order.GenericKeyOrder, func(k protoreflect.MapKey, v protoreflect.Value) bool {
371 if err = e.WriteName(k.String()); err != nil {
372 return false
373 }
374 if err = e.marshalSingular(v, fd.MapValue()); err != nil {
375 return false
376 }
377 return true
378 })
379 return err
380}