blob: e545feb5363037eda7d27f5e2c26e3b02400d041 [file] [log] [blame]
Andrea Campanella3614a922021-02-25 12:40:42 +01001// 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 "sort"
11
12 "google.golang.org/protobuf/internal/encoding/json"
13 "google.golang.org/protobuf/internal/encoding/messageset"
14 "google.golang.org/protobuf/internal/errors"
15 "google.golang.org/protobuf/internal/flags"
16 "google.golang.org/protobuf/internal/pragma"
17 "google.golang.org/protobuf/proto"
18 pref "google.golang.org/protobuf/reflect/protoreflect"
19 "google.golang.org/protobuf/reflect/protoregistry"
20)
21
22const defaultIndent = " "
23
24// Format formats the message as a multiline string.
25// This function is only intended for human consumption and ignores errors.
26// Do not depend on the output being stable. It may change over time across
27// different versions of the program.
28func Format(m proto.Message) string {
29 return MarshalOptions{Multiline: true}.Format(m)
30}
31
32// Marshal writes the given proto.Message in JSON format using default options.
33// Do not depend on the output being stable. It may change over time across
34// different versions of the program.
35func Marshal(m proto.Message) ([]byte, error) {
36 return MarshalOptions{}.Marshal(m)
37}
38
39// MarshalOptions is a configurable JSON format marshaler.
40type MarshalOptions struct {
41 pragma.NoUnkeyedLiterals
42
43 // Multiline specifies whether the marshaler should format the output in
44 // indented-form with every textual element on a new line.
45 // If Indent is an empty string, then an arbitrary indent is chosen.
46 Multiline bool
47
48 // Indent specifies the set of indentation characters to use in a multiline
49 // formatted output such that every entry is preceded by Indent and
50 // terminated by a newline. If non-empty, then Multiline is treated as true.
51 // Indent can only be composed of space or tab characters.
52 Indent string
53
54 // AllowPartial allows messages that have missing required fields to marshal
55 // without returning an error. If AllowPartial is false (the default),
56 // Marshal will return error if there are any missing required fields.
57 AllowPartial bool
58
59 // UseProtoNames uses proto field name instead of lowerCamelCase name in JSON
60 // field names.
61 UseProtoNames bool
62
63 // UseEnumNumbers emits enum values as numbers.
64 UseEnumNumbers bool
65
66 // EmitUnpopulated specifies whether to emit unpopulated fields. It does not
67 // emit unpopulated oneof fields or unpopulated extension fields.
68 // The JSON value emitted for unpopulated fields are as follows:
69 // ╔═══════╤════════════════════════════╗
70 // ║ JSON │ Protobuf field ║
71 // ╠═══════╪════════════════════════════╣
72 // ║ false │ proto3 boolean fields ║
73 // ║ 0 │ proto3 numeric fields ║
74 // ║ "" │ proto3 string/bytes fields ║
75 // ║ null │ proto2 scalar fields ║
76 // ║ null │ message fields ║
77 // ║ [] │ list fields ║
78 // ║ {} │ map fields ║
79 // ╚═══════╧════════════════════════════╝
80 EmitUnpopulated bool
81
82 // Resolver is used for looking up types when expanding google.protobuf.Any
83 // messages. If nil, this defaults to using protoregistry.GlobalTypes.
84 Resolver interface {
85 protoregistry.ExtensionTypeResolver
86 protoregistry.MessageTypeResolver
87 }
88}
89
90// Format formats the message as a string.
91// This method is only intended for human consumption and ignores errors.
92// Do not depend on the output being stable. It may change over time across
93// different versions of the program.
94func (o MarshalOptions) Format(m proto.Message) string {
95 if m == nil || !m.ProtoReflect().IsValid() {
96 return "<nil>" // invalid syntax, but okay since this is for debugging
97 }
98 o.AllowPartial = true
99 b, _ := o.Marshal(m)
100 return string(b)
101}
102
103// Marshal marshals the given proto.Message in the JSON format using options in
104// MarshalOptions. Do not depend on the output being stable. It may change over
105// time across different versions of the program.
106func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) {
107 if o.Multiline && o.Indent == "" {
108 o.Indent = defaultIndent
109 }
110 if o.Resolver == nil {
111 o.Resolver = protoregistry.GlobalTypes
112 }
113
114 internalEnc, err := json.NewEncoder(o.Indent)
115 if err != nil {
116 return nil, err
117 }
118
119 // Treat nil message interface as an empty message,
120 // in which case the output in an empty JSON object.
121 if m == nil {
122 return []byte("{}"), nil
123 }
124
125 enc := encoder{internalEnc, o}
126 if err := enc.marshalMessage(m.ProtoReflect()); err != nil {
127 return nil, err
128 }
129 if o.AllowPartial {
130 return enc.Bytes(), nil
131 }
132 return enc.Bytes(), proto.CheckInitialized(m)
133}
134
135type encoder struct {
136 *json.Encoder
137 opts MarshalOptions
138}
139
140// marshalMessage marshals the given protoreflect.Message.
141func (e encoder) marshalMessage(m pref.Message) error {
142 if isCustomType(m.Descriptor().FullName()) {
143 return e.marshalCustomType(m)
144 }
145
146 e.StartObject()
147 defer e.EndObject()
148 if err := e.marshalFields(m); err != nil {
149 return err
150 }
151
152 return nil
153}
154
155// marshalFields marshals the fields in the given protoreflect.Message.
156func (e encoder) marshalFields(m pref.Message) error {
157 messageDesc := m.Descriptor()
158 if !flags.ProtoLegacy && messageset.IsMessageSet(messageDesc) {
159 return errors.New("no support for proto1 MessageSets")
160 }
161
162 // Marshal out known fields.
163 fieldDescs := messageDesc.Fields()
164 for i := 0; i < fieldDescs.Len(); {
165 fd := fieldDescs.Get(i)
166 if od := fd.ContainingOneof(); od != nil {
167 fd = m.WhichOneof(od)
168 i += od.Fields().Len()
169 if fd == nil {
170 continue // unpopulated oneofs are not affected by EmitUnpopulated
171 }
172 } else {
173 i++
174 }
175
176 val := m.Get(fd)
177 if !m.Has(fd) {
178 if !e.opts.EmitUnpopulated {
179 continue
180 }
181 isProto2Scalar := fd.Syntax() == pref.Proto2 && fd.Default().IsValid()
182 isSingularMessage := fd.Cardinality() != pref.Repeated && fd.Message() != nil
183 if isProto2Scalar || isSingularMessage {
184 // Use invalid value to emit null.
185 val = pref.Value{}
186 }
187 }
188
189 name := fd.JSONName()
190 if e.opts.UseProtoNames {
191 name = string(fd.Name())
192 // Use type name for group field name.
193 if fd.Kind() == pref.GroupKind {
194 name = string(fd.Message().Name())
195 }
196 }
197 if err := e.WriteName(name); err != nil {
198 return err
199 }
200 if err := e.marshalValue(val, fd); err != nil {
201 return err
202 }
203 }
204
205 // Marshal out extensions.
206 if err := e.marshalExtensions(m); err != nil {
207 return err
208 }
209 return nil
210}
211
212// marshalValue marshals the given protoreflect.Value.
213func (e encoder) marshalValue(val pref.Value, fd pref.FieldDescriptor) error {
214 switch {
215 case fd.IsList():
216 return e.marshalList(val.List(), fd)
217 case fd.IsMap():
218 return e.marshalMap(val.Map(), fd)
219 default:
220 return e.marshalSingular(val, fd)
221 }
222}
223
224// marshalSingular marshals the given non-repeated field value. This includes
225// all scalar types, enums, messages, and groups.
226func (e encoder) marshalSingular(val pref.Value, fd pref.FieldDescriptor) error {
227 if !val.IsValid() {
228 e.WriteNull()
229 return nil
230 }
231
232 switch kind := fd.Kind(); kind {
233 case pref.BoolKind:
234 e.WriteBool(val.Bool())
235
236 case pref.StringKind:
237 if e.WriteString(val.String()) != nil {
238 return errors.InvalidUTF8(string(fd.FullName()))
239 }
240
241 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
242 e.WriteInt(val.Int())
243
244 case pref.Uint32Kind, pref.Fixed32Kind:
245 e.WriteUint(val.Uint())
246
247 case pref.Int64Kind, pref.Sint64Kind, pref.Uint64Kind,
248 pref.Sfixed64Kind, pref.Fixed64Kind:
249 // 64-bit integers are written out as JSON string.
250 e.WriteString(val.String())
251
252 case pref.FloatKind:
253 // Encoder.WriteFloat handles the special numbers NaN and infinites.
254 e.WriteFloat(val.Float(), 32)
255
256 case pref.DoubleKind:
257 // Encoder.WriteFloat handles the special numbers NaN and infinites.
258 e.WriteFloat(val.Float(), 64)
259
260 case pref.BytesKind:
261 e.WriteString(base64.StdEncoding.EncodeToString(val.Bytes()))
262
263 case pref.EnumKind:
264 if fd.Enum().FullName() == "google.protobuf.NullValue" {
265 e.WriteNull()
266 } else {
267 desc := fd.Enum().Values().ByNumber(val.Enum())
268 if e.opts.UseEnumNumbers || desc == nil {
269 e.WriteInt(int64(val.Enum()))
270 } else {
271 e.WriteString(string(desc.Name()))
272 }
273 }
274
275 case pref.MessageKind, pref.GroupKind:
276 if err := e.marshalMessage(val.Message()); err != nil {
277 return err
278 }
279
280 default:
281 panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind))
282 }
283 return nil
284}
285
286// marshalList marshals the given protoreflect.List.
287func (e encoder) marshalList(list pref.List, fd pref.FieldDescriptor) error {
288 e.StartArray()
289 defer e.EndArray()
290
291 for i := 0; i < list.Len(); i++ {
292 item := list.Get(i)
293 if err := e.marshalSingular(item, fd); err != nil {
294 return err
295 }
296 }
297 return nil
298}
299
300type mapEntry struct {
301 key pref.MapKey
302 value pref.Value
303}
304
305// marshalMap marshals given protoreflect.Map.
306func (e encoder) marshalMap(mmap pref.Map, fd pref.FieldDescriptor) error {
307 e.StartObject()
308 defer e.EndObject()
309
310 // Get a sorted list based on keyType first.
311 entries := make([]mapEntry, 0, mmap.Len())
312 mmap.Range(func(key pref.MapKey, val pref.Value) bool {
313 entries = append(entries, mapEntry{key: key, value: val})
314 return true
315 })
316 sortMap(fd.MapKey().Kind(), entries)
317
318 // Write out sorted list.
319 for _, entry := range entries {
320 if err := e.WriteName(entry.key.String()); err != nil {
321 return err
322 }
323 if err := e.marshalSingular(entry.value, fd.MapValue()); err != nil {
324 return err
325 }
326 }
327 return nil
328}
329
330// sortMap orders list based on value of key field for deterministic ordering.
331func sortMap(keyKind pref.Kind, values []mapEntry) {
332 sort.Slice(values, func(i, j int) bool {
333 switch keyKind {
334 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind,
335 pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
336 return values[i].key.Int() < values[j].key.Int()
337
338 case pref.Uint32Kind, pref.Fixed32Kind,
339 pref.Uint64Kind, pref.Fixed64Kind:
340 return values[i].key.Uint() < values[j].key.Uint()
341 }
342 return values[i].key.String() < values[j].key.String()
343 })
344}
345
346// marshalExtensions marshals extension fields.
347func (e encoder) marshalExtensions(m pref.Message) error {
348 type entry struct {
349 key string
350 value pref.Value
351 desc pref.FieldDescriptor
352 }
353
354 // Get a sorted list based on field key first.
355 var entries []entry
356 m.Range(func(fd pref.FieldDescriptor, v pref.Value) bool {
357 if !fd.IsExtension() {
358 return true
359 }
360
361 // For MessageSet extensions, the name used is the parent message.
362 name := fd.FullName()
363 if messageset.IsMessageSetExtension(fd) {
364 name = name.Parent()
365 }
366
367 // Use [name] format for JSON field name.
368 entries = append(entries, entry{
369 key: string(name),
370 value: v,
371 desc: fd,
372 })
373 return true
374 })
375
376 // Sort extensions lexicographically.
377 sort.Slice(entries, func(i, j int) bool {
378 return entries[i].key < entries[j].key
379 })
380
381 // Write out sorted list.
382 for _, entry := range entries {
383 // JSON field name is the proto field name enclosed in [], similar to
384 // textproto. This is consistent with Go v1 lib. C++ lib v3.7.0 does not
385 // marshal out extension fields.
386 if err := e.WriteName("[" + entry.key + "]"); err != nil {
387 return err
388 }
389 if err := e.marshalValue(entry.value, entry.desc); err != nil {
390 return err
391 }
392 }
393 return nil
394}