blob: 93750915d86b5ad8b332665a154eedd0744c54d6 [file] [log] [blame]
Herbie Ong7b828bc2019-02-08 19:56:24 -08001// 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 jsonpb
6
7import (
8 "encoding/base64"
Herbie Ong0b0f4032019-03-18 19:06:15 -07009 "fmt"
Herbie Ong7b828bc2019-02-08 19:56:24 -080010 "sort"
11
Herbie Ong87608a72019-03-06 14:32:24 -080012 "github.com/golang/protobuf/v2/internal/encoding/json"
Herbie Ong7b828bc2019-02-08 19:56:24 -080013 "github.com/golang/protobuf/v2/internal/errors"
14 "github.com/golang/protobuf/v2/internal/pragma"
15 "github.com/golang/protobuf/v2/proto"
16 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
Herbie Ong0b0f4032019-03-18 19:06:15 -070017 "github.com/golang/protobuf/v2/reflect/protoregistry"
Herbie Ong7b828bc2019-02-08 19:56:24 -080018)
19
20// Marshal writes the given proto.Message in JSON format using default options.
21func Marshal(m proto.Message) ([]byte, error) {
22 return MarshalOptions{}.Marshal(m)
23}
24
25// MarshalOptions is a configurable JSON format marshaler.
26type MarshalOptions struct {
27 pragma.NoUnkeyedLiterals
28
Herbie Ong329be5b2019-03-27 14:47:59 -070029 // AllowPartial allows messages that have missing required fields to marshal
30 // without returning an error. If AllowPartial is false (the default),
31 // Marshal will return error if there are any missing required fields.
32 AllowPartial bool
33
Herbie Ong0b0f4032019-03-18 19:06:15 -070034 // If Indent is a non-empty string, it causes entries for an Array or Object
35 // to be preceded by the indent and trailed by a newline. Indent can only be
36 // composed of space or tab characters.
37 Indent string
38
39 // Resolver is the registry used for type lookups when marshaling
40 // google.protobuf.Any messages. If Resolver is not set, marshaling will
41 // default to using protoregistry.GlobalTypes.
42 Resolver *protoregistry.Types
Herbie Ong822de2d2019-03-27 13:16:23 -070043
44 encoder *json.Encoder
Herbie Ong7b828bc2019-02-08 19:56:24 -080045}
46
Herbie Ong0b0f4032019-03-18 19:06:15 -070047// Marshal marshals the given proto.Message in the JSON format using options in
48// MarshalOptions.
Herbie Ong7b828bc2019-02-08 19:56:24 -080049func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) {
Herbie Ong822de2d2019-03-27 13:16:23 -070050 var err error
51 o.encoder, err = json.NewEncoder(o.Indent)
Herbie Ong87608a72019-03-06 14:32:24 -080052 if err != nil {
53 return nil, err
54 }
Herbie Ong822de2d2019-03-27 13:16:23 -070055 if o.Resolver == nil {
56 o.Resolver = protoregistry.GlobalTypes
57 }
Herbie Ong87608a72019-03-06 14:32:24 -080058
59 var nerr errors.NonFatal
Herbie Ong822de2d2019-03-27 13:16:23 -070060 err = o.marshalMessage(m.ProtoReflect())
Herbie Ong7b828bc2019-02-08 19:56:24 -080061 if !nerr.Merge(err) {
62 return nil, err
63 }
Damien Neil4686e232019-04-05 13:31:40 -070064 if !o.AllowPartial {
65 nerr.Merge(proto.IsInitialized(m))
66 }
Herbie Ong822de2d2019-03-27 13:16:23 -070067 return o.encoder.Bytes(), nerr.E
Herbie Ong87608a72019-03-06 14:32:24 -080068}
69
70// marshalMessage marshals the given protoreflect.Message.
Herbie Ong822de2d2019-03-27 13:16:23 -070071func (o MarshalOptions) marshalMessage(m pref.Message) error {
Herbie Ong0b0f4032019-03-18 19:06:15 -070072 var nerr errors.NonFatal
73
74 if isCustomType(m.Type().FullName()) {
Herbie Ong822de2d2019-03-27 13:16:23 -070075 return o.marshalCustomType(m)
Herbie Ong0b0f4032019-03-18 19:06:15 -070076 }
77
Herbie Ong822de2d2019-03-27 13:16:23 -070078 o.encoder.StartObject()
79 defer o.encoder.EndObject()
80 if err := o.marshalFields(m); !nerr.Merge(err) {
Herbie Ong0b0f4032019-03-18 19:06:15 -070081 return err
82 }
Herbie Ong87608a72019-03-06 14:32:24 -080083
Herbie Ong0b0f4032019-03-18 19:06:15 -070084 return nerr.E
85}
86
87// marshalFields marshals the fields in the given protoreflect.Message.
Herbie Ong822de2d2019-03-27 13:16:23 -070088func (o MarshalOptions) marshalFields(m pref.Message) error {
Herbie Ong87608a72019-03-06 14:32:24 -080089 var nerr errors.NonFatal
90 fieldDescs := m.Type().Fields()
Herbie Ong7b828bc2019-02-08 19:56:24 -080091 knownFields := m.KnownFields()
Herbie Ong87608a72019-03-06 14:32:24 -080092
Herbie Ongf83d5bb2019-03-14 00:01:27 -070093 // Marshal out known fields.
Herbie Ong87608a72019-03-06 14:32:24 -080094 for i := 0; i < fieldDescs.Len(); i++ {
Herbie Ong7b828bc2019-02-08 19:56:24 -080095 fd := fieldDescs.Get(i)
96 num := fd.Number()
97
98 if !knownFields.Has(num) {
Herbie Ong7b828bc2019-02-08 19:56:24 -080099 continue
100 }
101
Herbie Ong87608a72019-03-06 14:32:24 -0800102 name := fd.JSONName()
Herbie Ong1c7462c2019-03-22 17:56:55 -0700103 val := knownFields.Get(num)
Herbie Ong822de2d2019-03-27 13:16:23 -0700104 if err := o.encoder.WriteName(name); !nerr.Merge(err) {
Herbie Ong87608a72019-03-06 14:32:24 -0800105 return err
106 }
Herbie Ong822de2d2019-03-27 13:16:23 -0700107 if err := o.marshalValue(val, fd); !nerr.Merge(err) {
Herbie Ong87608a72019-03-06 14:32:24 -0800108 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800109 }
110 }
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700111
112 // Marshal out extensions.
Herbie Ong822de2d2019-03-27 13:16:23 -0700113 if err := o.marshalExtensions(knownFields); !nerr.Merge(err) {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700114 return err
115 }
Herbie Ong87608a72019-03-06 14:32:24 -0800116 return nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -0800117}
118
Herbie Ong87608a72019-03-06 14:32:24 -0800119// marshalValue marshals the given protoreflect.Value.
Herbie Ong822de2d2019-03-27 13:16:23 -0700120func (o MarshalOptions) marshalValue(val pref.Value, fd pref.FieldDescriptor) error {
Herbie Ong7b828bc2019-02-08 19:56:24 -0800121 var nerr errors.NonFatal
Herbie Ong7b828bc2019-02-08 19:56:24 -0800122 if fd.Cardinality() == pref.Repeated {
123 // Map or repeated fields.
124 if fd.IsMap() {
Herbie Ong822de2d2019-03-27 13:16:23 -0700125 if err := o.marshalMap(val.Map(), fd); !nerr.Merge(err) {
Herbie Ong87608a72019-03-06 14:32:24 -0800126 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800127 }
128 } else {
Herbie Ong822de2d2019-03-27 13:16:23 -0700129 if err := o.marshalList(val.List(), fd); !nerr.Merge(err) {
Herbie Ong87608a72019-03-06 14:32:24 -0800130 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800131 }
132 }
133 } else {
134 // Required or optional fields.
Herbie Ong822de2d2019-03-27 13:16:23 -0700135 if err := o.marshalSingular(val, fd); !nerr.Merge(err) {
Herbie Ong87608a72019-03-06 14:32:24 -0800136 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800137 }
138 }
Herbie Ong87608a72019-03-06 14:32:24 -0800139 return nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -0800140}
141
Herbie Ong87608a72019-03-06 14:32:24 -0800142// marshalSingular marshals the given non-repeated field value. This includes
143// all scalar types, enums, messages, and groups.
Herbie Ong822de2d2019-03-27 13:16:23 -0700144func (o MarshalOptions) marshalSingular(val pref.Value, fd pref.FieldDescriptor) error {
Herbie Ong87608a72019-03-06 14:32:24 -0800145 var nerr errors.NonFatal
146 switch kind := fd.Kind(); kind {
147 case pref.BoolKind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700148 o.encoder.WriteBool(val.Bool())
Herbie Ong87608a72019-03-06 14:32:24 -0800149
150 case pref.StringKind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700151 if err := o.encoder.WriteString(val.String()); !nerr.Merge(err) {
Herbie Ong87608a72019-03-06 14:32:24 -0800152 return err
153 }
154
155 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700156 o.encoder.WriteInt(val.Int())
Herbie Ong87608a72019-03-06 14:32:24 -0800157
158 case pref.Uint32Kind, pref.Fixed32Kind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700159 o.encoder.WriteUint(val.Uint())
Herbie Ong7b828bc2019-02-08 19:56:24 -0800160
161 case pref.Int64Kind, pref.Sint64Kind, pref.Uint64Kind,
162 pref.Sfixed64Kind, pref.Fixed64Kind:
Herbie Ong87608a72019-03-06 14:32:24 -0800163 // 64-bit integers are written out as JSON string.
Herbie Ong822de2d2019-03-27 13:16:23 -0700164 o.encoder.WriteString(val.String())
Herbie Ong7b828bc2019-02-08 19:56:24 -0800165
Herbie Ong87608a72019-03-06 14:32:24 -0800166 case pref.FloatKind:
167 // Encoder.WriteFloat handles the special numbers NaN and infinites.
Herbie Ong822de2d2019-03-27 13:16:23 -0700168 o.encoder.WriteFloat(val.Float(), 32)
Herbie Ong87608a72019-03-06 14:32:24 -0800169
170 case pref.DoubleKind:
171 // Encoder.WriteFloat handles the special numbers NaN and infinites.
Herbie Ong822de2d2019-03-27 13:16:23 -0700172 o.encoder.WriteFloat(val.Float(), 64)
Herbie Ong7b828bc2019-02-08 19:56:24 -0800173
174 case pref.BytesKind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700175 err := o.encoder.WriteString(base64.StdEncoding.EncodeToString(val.Bytes()))
Herbie Ong87608a72019-03-06 14:32:24 -0800176 if !nerr.Merge(err) {
177 return err
178 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800179
180 case pref.EnumKind:
Joe Tsaid24bc722019-04-15 23:39:09 -0700181 if fd.Enum().FullName() == "google.protobuf.NullValue" {
Herbie Ong822de2d2019-03-27 13:16:23 -0700182 o.encoder.WriteNull()
Joe Tsaid24bc722019-04-15 23:39:09 -0700183 } else if desc := fd.Enum().Values().ByNumber(val.Enum()); desc != nil {
Herbie Ong822de2d2019-03-27 13:16:23 -0700184 err := o.encoder.WriteString(string(desc.Name()))
Herbie Ong87608a72019-03-06 14:32:24 -0800185 if !nerr.Merge(err) {
186 return err
187 }
188 } else {
189 // Use numeric value if there is no enum value descriptor.
Joe Tsaid24bc722019-04-15 23:39:09 -0700190 o.encoder.WriteInt(int64(val.Enum()))
Herbie Ong7b828bc2019-02-08 19:56:24 -0800191 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800192
193 case pref.MessageKind, pref.GroupKind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700194 if err := o.marshalMessage(val.Message()); !nerr.Merge(err) {
Herbie Ong87608a72019-03-06 14:32:24 -0800195 return err
196 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800197
Herbie Ong87608a72019-03-06 14:32:24 -0800198 default:
Herbie Ong0b0f4032019-03-18 19:06:15 -0700199 panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind))
Herbie Ong87608a72019-03-06 14:32:24 -0800200 }
201 return nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -0800202}
203
Herbie Ong87608a72019-03-06 14:32:24 -0800204// marshalList marshals the given protoreflect.List.
Herbie Ong822de2d2019-03-27 13:16:23 -0700205func (o MarshalOptions) marshalList(list pref.List, fd pref.FieldDescriptor) error {
206 o.encoder.StartArray()
207 defer o.encoder.EndArray()
Herbie Ong87608a72019-03-06 14:32:24 -0800208
Herbie Ong7b828bc2019-02-08 19:56:24 -0800209 var nerr errors.NonFatal
Herbie Ong87608a72019-03-06 14:32:24 -0800210 for i := 0; i < list.Len(); i++ {
Herbie Ong7b828bc2019-02-08 19:56:24 -0800211 item := list.Get(i)
Herbie Ong822de2d2019-03-27 13:16:23 -0700212 if err := o.marshalSingular(item, fd); !nerr.Merge(err) {
Herbie Ong87608a72019-03-06 14:32:24 -0800213 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800214 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800215 }
Herbie Ong87608a72019-03-06 14:32:24 -0800216 return nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -0800217}
218
219type mapEntry struct {
220 key pref.MapKey
221 value pref.Value
222}
223
Herbie Ong87608a72019-03-06 14:32:24 -0800224// marshalMap marshals given protoreflect.Map.
Herbie Ong822de2d2019-03-27 13:16:23 -0700225func (o MarshalOptions) marshalMap(mmap pref.Map, fd pref.FieldDescriptor) error {
226 o.encoder.StartObject()
227 defer o.encoder.EndObject()
Herbie Ong87608a72019-03-06 14:32:24 -0800228
Joe Tsaid24bc722019-04-15 23:39:09 -0700229 msgFields := fd.Message().Fields()
Herbie Ong7b828bc2019-02-08 19:56:24 -0800230 keyType := msgFields.ByNumber(1)
231 valType := msgFields.ByNumber(2)
232
233 // Get a sorted list based on keyType first.
234 entries := make([]mapEntry, 0, mmap.Len())
235 mmap.Range(func(key pref.MapKey, val pref.Value) bool {
236 entries = append(entries, mapEntry{key: key, value: val})
237 return true
238 })
239 sortMap(keyType.Kind(), entries)
240
Herbie Ong87608a72019-03-06 14:32:24 -0800241 // Write out sorted list.
Herbie Ong7b828bc2019-02-08 19:56:24 -0800242 var nerr errors.NonFatal
Herbie Ong7b828bc2019-02-08 19:56:24 -0800243 for _, entry := range entries {
Herbie Ong822de2d2019-03-27 13:16:23 -0700244 if err := o.encoder.WriteName(entry.key.String()); !nerr.Merge(err) {
Herbie Ong87608a72019-03-06 14:32:24 -0800245 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800246 }
Herbie Ong822de2d2019-03-27 13:16:23 -0700247 if err := o.marshalSingular(entry.value, valType); !nerr.Merge(err) {
Herbie Ong87608a72019-03-06 14:32:24 -0800248 return err
249 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800250 }
Herbie Ong87608a72019-03-06 14:32:24 -0800251 return nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -0800252}
253
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700254// sortMap orders list based on value of key field for deterministic ordering.
Herbie Ong7b828bc2019-02-08 19:56:24 -0800255func sortMap(keyKind pref.Kind, values []mapEntry) {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700256 sort.Slice(values, func(i, j int) bool {
257 switch keyKind {
258 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind,
259 pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
Herbie Ong7b828bc2019-02-08 19:56:24 -0800260 return values[i].key.Int() < values[j].key.Int()
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700261
262 case pref.Uint32Kind, pref.Fixed32Kind,
263 pref.Uint64Kind, pref.Fixed64Kind:
Herbie Ong7b828bc2019-02-08 19:56:24 -0800264 return values[i].key.Uint() < values[j].key.Uint()
265 }
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700266 return values[i].key.String() < values[j].key.String()
267 })
268}
269
270// marshalExtensions marshals extension fields.
Herbie Ong822de2d2019-03-27 13:16:23 -0700271func (o MarshalOptions) marshalExtensions(knownFields pref.KnownFields) error {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700272 type xtEntry struct {
273 key string
274 value pref.Value
275 xtType pref.ExtensionType
Herbie Ong7b828bc2019-02-08 19:56:24 -0800276 }
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700277
278 xtTypes := knownFields.ExtensionTypes()
279
280 // Get a sorted list based on field key first.
281 entries := make([]xtEntry, 0, xtTypes.Len())
282 xtTypes.Range(func(xt pref.ExtensionType) bool {
283 name := xt.FullName()
284 // If extended type is a MessageSet, set field name to be the message type name.
285 if isMessageSetExtension(xt) {
Joe Tsaid24bc722019-04-15 23:39:09 -0700286 name = xt.Message().FullName()
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700287 }
288
289 num := xt.Number()
290 if knownFields.Has(num) {
291 // Use [name] format for JSON field name.
292 pval := knownFields.Get(num)
293 entries = append(entries, xtEntry{
294 key: string(name),
295 value: pval,
296 xtType: xt,
297 })
298 }
299 return true
300 })
301
302 // Sort extensions lexicographically.
303 sort.Slice(entries, func(i, j int) bool {
304 return entries[i].key < entries[j].key
305 })
306
307 // Write out sorted list.
308 var nerr errors.NonFatal
309 for _, entry := range entries {
310 // JSON field name is the proto field name enclosed in [], similar to
311 // textproto. This is consistent with Go v1 lib. C++ lib v3.7.0 does not
312 // marshal out extension fields.
Herbie Ong822de2d2019-03-27 13:16:23 -0700313 if err := o.encoder.WriteName("[" + entry.key + "]"); !nerr.Merge(err) {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700314 return err
315 }
Herbie Ong822de2d2019-03-27 13:16:23 -0700316 if err := o.marshalValue(entry.value, entry.xtType); !nerr.Merge(err) {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700317 return err
318 }
319 }
320 return nerr.E
321}
322
323// isMessageSetExtension reports whether extension extends a message set.
324func isMessageSetExtension(xt pref.ExtensionType) bool {
325 if xt.Name() != "message_set_extension" {
326 return false
327 }
Joe Tsaid24bc722019-04-15 23:39:09 -0700328 md := xt.Message()
329 if md == nil {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700330 return false
331 }
Joe Tsaid24bc722019-04-15 23:39:09 -0700332 if xt.FullName().Parent() != md.FullName() {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700333 return false
334 }
Joe Tsaid24bc722019-04-15 23:39:09 -0700335 xmd, ok := xt.Extendee().(interface{ IsMessageSet() bool })
336 return ok && xmd.IsMessageSet()
Herbie Ong7b828bc2019-02-08 19:56:24 -0800337}