blob: 1662e40570ff28bb9cb035804296dfb1ac4f7b4a [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
Damien Neil5c5b5312019-05-14 12:44:37 -07005package protojson
Herbie Ong7b828bc2019-02-08 19:56:24 -08006
7import (
8 "encoding/base64"
Herbie Ong0b0f4032019-03-18 19:06:15 -07009 "fmt"
Herbie Ong7b828bc2019-02-08 19:56:24 -080010 "sort"
11
Damien Neile89e6242019-05-13 23:55:40 -070012 "google.golang.org/protobuf/internal/encoding/json"
Joe Tsai5ae10aa2019-07-11 18:23:08 -070013 "google.golang.org/protobuf/internal/encoding/messageset"
14 "google.golang.org/protobuf/internal/errors"
15 "google.golang.org/protobuf/internal/flags"
Damien Neile89e6242019-05-13 23:55:40 -070016 "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"
Herbie Ong7b828bc2019-02-08 19:56:24 -080020)
21
22// Marshal writes the given proto.Message in JSON format using default options.
23func Marshal(m proto.Message) ([]byte, error) {
24 return MarshalOptions{}.Marshal(m)
25}
26
27// MarshalOptions is a configurable JSON format marshaler.
28type MarshalOptions struct {
29 pragma.NoUnkeyedLiterals
Herbie Ong984e5282019-09-06 00:29:48 -070030 encoder *json.Encoder
Herbie Ong7b828bc2019-02-08 19:56:24 -080031
Herbie Ong329be5b2019-03-27 14:47:59 -070032 // AllowPartial allows messages that have missing required fields to marshal
33 // without returning an error. If AllowPartial is false (the default),
34 // Marshal will return error if there are any missing required fields.
35 AllowPartial bool
36
Herbie Ong956cd6d2019-09-06 15:17:22 -070037 // UseProtoNames uses proto field name instead of lowerCamelCase name in JSON
38 // field names.
39 UseProtoNames bool
40
Herbie Ong9111f3b2019-09-06 14:35:09 -070041 // UseEnumNumbers emits enum values as numbers.
42 UseEnumNumbers bool
43
Herbie Ong984e5282019-09-06 00:29:48 -070044 // EmitUnpopulated specifies whether to emit unpopulated fields. It does not
45 // emit unpopulated oneof fields or unpopulated extension fields.
46 // The JSON value emitted for unpopulated fields are as follows:
Herbie Ong956cd6d2019-09-06 15:17:22 -070047 // ╔═══════╤════════════════════════════╗
48 // ║ JSON │ Protobuf field ║
49 // ╠═══════╪════════════════════════════╣
50 // ║ false │ proto3 boolean fields ║
51 // ║ 0 │ proto3 numeric fields ║
52 // ║ "" │ proto3 string/bytes fields ║
53 // ║ null │ proto2 scalar fields ║
54 // ║ null │ message fields ║
55 // ║ [] │ list fields ║
56 // ║ {} │ map fields ║
57 // ╚═══════╧════════════════════════════╝
Herbie Ong984e5282019-09-06 00:29:48 -070058 EmitUnpopulated bool
59
Herbie Ong0b0f4032019-03-18 19:06:15 -070060 // If Indent is a non-empty string, it causes entries for an Array or Object
61 // to be preceded by the indent and trailed by a newline. Indent can only be
62 // composed of space or tab characters.
63 Indent string
64
Joe Tsai1c283042019-05-14 14:28:19 -070065 // Resolver is used for looking up types when expanding google.protobuf.Any
66 // messages. If nil, this defaults to using protoregistry.GlobalTypes.
67 Resolver interface {
Damien Neil95faac22019-06-19 10:03:37 -070068 protoregistry.ExtensionTypeResolver
Joe Tsai1c283042019-05-14 14:28:19 -070069 protoregistry.MessageTypeResolver
70 }
Herbie Ong7b828bc2019-02-08 19:56:24 -080071}
72
Herbie Ong0b0f4032019-03-18 19:06:15 -070073// Marshal marshals the given proto.Message in the JSON format using options in
74// MarshalOptions.
Herbie Ong7b828bc2019-02-08 19:56:24 -080075func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) {
Herbie Ong822de2d2019-03-27 13:16:23 -070076 var err error
77 o.encoder, err = json.NewEncoder(o.Indent)
Herbie Ong87608a72019-03-06 14:32:24 -080078 if err != nil {
79 return nil, err
80 }
Herbie Ong822de2d2019-03-27 13:16:23 -070081 if o.Resolver == nil {
82 o.Resolver = protoregistry.GlobalTypes
83 }
Herbie Ong87608a72019-03-06 14:32:24 -080084
Herbie Ong822de2d2019-03-27 13:16:23 -070085 err = o.marshalMessage(m.ProtoReflect())
Damien Neil8c86fc52019-06-19 09:28:29 -070086 if err != nil {
Herbie Ong7b828bc2019-02-08 19:56:24 -080087 return nil, err
88 }
Damien Neil8c86fc52019-06-19 09:28:29 -070089 if o.AllowPartial {
90 return o.encoder.Bytes(), nil
Damien Neil4686e232019-04-05 13:31:40 -070091 }
Damien Neil8c86fc52019-06-19 09:28:29 -070092 return o.encoder.Bytes(), proto.IsInitialized(m)
Herbie Ong87608a72019-03-06 14:32:24 -080093}
94
95// marshalMessage marshals the given protoreflect.Message.
Herbie Ong822de2d2019-03-27 13:16:23 -070096func (o MarshalOptions) marshalMessage(m pref.Message) error {
Joe Tsai0fc49f82019-05-01 12:29:25 -070097 if isCustomType(m.Descriptor().FullName()) {
Herbie Ong822de2d2019-03-27 13:16:23 -070098 return o.marshalCustomType(m)
Herbie Ong0b0f4032019-03-18 19:06:15 -070099 }
100
Herbie Ong822de2d2019-03-27 13:16:23 -0700101 o.encoder.StartObject()
102 defer o.encoder.EndObject()
Damien Neil8c86fc52019-06-19 09:28:29 -0700103 if err := o.marshalFields(m); err != nil {
Herbie Ong0b0f4032019-03-18 19:06:15 -0700104 return err
105 }
Herbie Ong87608a72019-03-06 14:32:24 -0800106
Damien Neil8c86fc52019-06-19 09:28:29 -0700107 return nil
Herbie Ong0b0f4032019-03-18 19:06:15 -0700108}
109
110// marshalFields marshals the fields in the given protoreflect.Message.
Herbie Ong822de2d2019-03-27 13:16:23 -0700111func (o MarshalOptions) marshalFields(m pref.Message) error {
Joe Tsai5ae10aa2019-07-11 18:23:08 -0700112 messageDesc := m.Descriptor()
Joe Tsai1799d112019-08-08 13:31:59 -0700113 if !flags.ProtoLegacy && messageset.IsMessageSet(messageDesc) {
Joe Tsai5ae10aa2019-07-11 18:23:08 -0700114 return errors.New("no support for proto1 MessageSets")
115 }
116
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700117 // Marshal out known fields.
Joe Tsai5ae10aa2019-07-11 18:23:08 -0700118 fieldDescs := messageDesc.Fields()
Herbie Ong87608a72019-03-06 14:32:24 -0800119 for i := 0; i < fieldDescs.Len(); i++ {
Herbie Ong7b828bc2019-02-08 19:56:24 -0800120 fd := fieldDescs.Get(i)
Herbie Ong984e5282019-09-06 00:29:48 -0700121 val := m.Get(fd)
Joe Tsai378c1322019-04-25 23:48:08 -0700122 if !m.Has(fd) {
Herbie Ong984e5282019-09-06 00:29:48 -0700123 if !o.EmitUnpopulated || fd.ContainingOneof() != nil {
124 continue
125 }
126 isProto2Scalar := fd.Syntax() == pref.Proto2 && fd.Default().IsValid()
127 isSingularMessage := fd.Cardinality() != pref.Repeated && fd.Message() != nil
128 if isProto2Scalar || isSingularMessage {
129 // Use invalid value to emit null.
130 val = pref.Value{}
131 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800132 }
133
Herbie Ong87608a72019-03-06 14:32:24 -0800134 name := fd.JSONName()
Herbie Ong956cd6d2019-09-06 15:17:22 -0700135 if o.UseProtoNames {
136 name = string(fd.Name())
137 // Use type name for group field name.
138 if fd.Kind() == pref.GroupKind {
139 name = string(fd.Message().Name())
140 }
141 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700142 if err := o.encoder.WriteName(name); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800143 return err
144 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700145 if err := o.marshalValue(val, fd); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800146 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800147 }
148 }
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700149
150 // Marshal out extensions.
Damien Neil8c86fc52019-06-19 09:28:29 -0700151 if err := o.marshalExtensions(m); err != nil {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700152 return err
153 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700154 return nil
Herbie Ong7b828bc2019-02-08 19:56:24 -0800155}
156
Herbie Ong87608a72019-03-06 14:32:24 -0800157// marshalValue marshals the given protoreflect.Value.
Herbie Ong822de2d2019-03-27 13:16:23 -0700158func (o MarshalOptions) marshalValue(val pref.Value, fd pref.FieldDescriptor) error {
Joe Tsaiac31a352019-05-13 14:32:56 -0700159 switch {
160 case fd.IsList():
161 return o.marshalList(val.List(), fd)
162 case fd.IsMap():
163 return o.marshalMap(val.Map(), fd)
164 default:
165 return o.marshalSingular(val, fd)
Herbie Ong7b828bc2019-02-08 19:56:24 -0800166 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800167}
168
Herbie Ong87608a72019-03-06 14:32:24 -0800169// marshalSingular marshals the given non-repeated field value. This includes
170// all scalar types, enums, messages, and groups.
Herbie Ong822de2d2019-03-27 13:16:23 -0700171func (o MarshalOptions) marshalSingular(val pref.Value, fd pref.FieldDescriptor) error {
Herbie Ong984e5282019-09-06 00:29:48 -0700172 if !val.IsValid() {
173 o.encoder.WriteNull()
174 return nil
175 }
176
Herbie Ong87608a72019-03-06 14:32:24 -0800177 switch kind := fd.Kind(); kind {
178 case pref.BoolKind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700179 o.encoder.WriteBool(val.Bool())
Herbie Ong87608a72019-03-06 14:32:24 -0800180
181 case pref.StringKind:
Damien Neil8c86fc52019-06-19 09:28:29 -0700182 if err := o.encoder.WriteString(val.String()); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800183 return err
184 }
185
186 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700187 o.encoder.WriteInt(val.Int())
Herbie Ong87608a72019-03-06 14:32:24 -0800188
189 case pref.Uint32Kind, pref.Fixed32Kind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700190 o.encoder.WriteUint(val.Uint())
Herbie Ong7b828bc2019-02-08 19:56:24 -0800191
192 case pref.Int64Kind, pref.Sint64Kind, pref.Uint64Kind,
193 pref.Sfixed64Kind, pref.Fixed64Kind:
Herbie Ong87608a72019-03-06 14:32:24 -0800194 // 64-bit integers are written out as JSON string.
Herbie Ong822de2d2019-03-27 13:16:23 -0700195 o.encoder.WriteString(val.String())
Herbie Ong7b828bc2019-02-08 19:56:24 -0800196
Herbie Ong87608a72019-03-06 14:32:24 -0800197 case pref.FloatKind:
198 // Encoder.WriteFloat handles the special numbers NaN and infinites.
Herbie Ong822de2d2019-03-27 13:16:23 -0700199 o.encoder.WriteFloat(val.Float(), 32)
Herbie Ong87608a72019-03-06 14:32:24 -0800200
201 case pref.DoubleKind:
202 // Encoder.WriteFloat handles the special numbers NaN and infinites.
Herbie Ong822de2d2019-03-27 13:16:23 -0700203 o.encoder.WriteFloat(val.Float(), 64)
Herbie Ong7b828bc2019-02-08 19:56:24 -0800204
205 case pref.BytesKind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700206 err := o.encoder.WriteString(base64.StdEncoding.EncodeToString(val.Bytes()))
Damien Neil8c86fc52019-06-19 09:28:29 -0700207 if err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800208 return err
209 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800210
211 case pref.EnumKind:
Joe Tsaid24bc722019-04-15 23:39:09 -0700212 if fd.Enum().FullName() == "google.protobuf.NullValue" {
Herbie Ong822de2d2019-03-27 13:16:23 -0700213 o.encoder.WriteNull()
Herbie Ong87608a72019-03-06 14:32:24 -0800214 } else {
Herbie Ong9111f3b2019-09-06 14:35:09 -0700215 desc := fd.Enum().Values().ByNumber(val.Enum())
216 if o.UseEnumNumbers || desc == nil {
217 o.encoder.WriteInt(int64(val.Enum()))
218 } else {
219 err := o.encoder.WriteString(string(desc.Name()))
220 if err != nil {
221 return err
222 }
223 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800224 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800225
226 case pref.MessageKind, pref.GroupKind:
Damien Neil8c86fc52019-06-19 09:28:29 -0700227 if err := o.marshalMessage(val.Message()); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800228 return err
229 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800230
Herbie Ong87608a72019-03-06 14:32:24 -0800231 default:
Herbie Ong0b0f4032019-03-18 19:06:15 -0700232 panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind))
Herbie Ong87608a72019-03-06 14:32:24 -0800233 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700234 return nil
Herbie Ong7b828bc2019-02-08 19:56:24 -0800235}
236
Herbie Ong87608a72019-03-06 14:32:24 -0800237// marshalList marshals the given protoreflect.List.
Herbie Ong822de2d2019-03-27 13:16:23 -0700238func (o MarshalOptions) marshalList(list pref.List, fd pref.FieldDescriptor) error {
239 o.encoder.StartArray()
240 defer o.encoder.EndArray()
Herbie Ong87608a72019-03-06 14:32:24 -0800241
Herbie Ong87608a72019-03-06 14:32:24 -0800242 for i := 0; i < list.Len(); i++ {
Herbie Ong7b828bc2019-02-08 19:56:24 -0800243 item := list.Get(i)
Damien Neil8c86fc52019-06-19 09:28:29 -0700244 if err := o.marshalSingular(item, fd); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800245 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800246 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800247 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700248 return nil
Herbie Ong7b828bc2019-02-08 19:56:24 -0800249}
250
251type mapEntry struct {
252 key pref.MapKey
253 value pref.Value
254}
255
Herbie Ong87608a72019-03-06 14:32:24 -0800256// marshalMap marshals given protoreflect.Map.
Herbie Ong822de2d2019-03-27 13:16:23 -0700257func (o MarshalOptions) marshalMap(mmap pref.Map, fd pref.FieldDescriptor) error {
258 o.encoder.StartObject()
259 defer o.encoder.EndObject()
Herbie Ong87608a72019-03-06 14:32:24 -0800260
Herbie Ong7b828bc2019-02-08 19:56:24 -0800261 // Get a sorted list based on keyType first.
262 entries := make([]mapEntry, 0, mmap.Len())
263 mmap.Range(func(key pref.MapKey, val pref.Value) bool {
264 entries = append(entries, mapEntry{key: key, value: val})
265 return true
266 })
Joe Tsaiac31a352019-05-13 14:32:56 -0700267 sortMap(fd.MapKey().Kind(), entries)
Herbie Ong7b828bc2019-02-08 19:56:24 -0800268
Herbie Ong87608a72019-03-06 14:32:24 -0800269 // Write out sorted list.
Herbie Ong7b828bc2019-02-08 19:56:24 -0800270 for _, entry := range entries {
Damien Neil8c86fc52019-06-19 09:28:29 -0700271 if err := o.encoder.WriteName(entry.key.String()); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800272 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800273 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700274 if err := o.marshalSingular(entry.value, fd.MapValue()); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800275 return err
276 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800277 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700278 return nil
Herbie Ong7b828bc2019-02-08 19:56:24 -0800279}
280
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700281// sortMap orders list based on value of key field for deterministic ordering.
Herbie Ong7b828bc2019-02-08 19:56:24 -0800282func sortMap(keyKind pref.Kind, values []mapEntry) {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700283 sort.Slice(values, func(i, j int) bool {
284 switch keyKind {
285 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind,
286 pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
Herbie Ong7b828bc2019-02-08 19:56:24 -0800287 return values[i].key.Int() < values[j].key.Int()
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700288
289 case pref.Uint32Kind, pref.Fixed32Kind,
290 pref.Uint64Kind, pref.Fixed64Kind:
Herbie Ong7b828bc2019-02-08 19:56:24 -0800291 return values[i].key.Uint() < values[j].key.Uint()
292 }
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700293 return values[i].key.String() < values[j].key.String()
294 })
295}
296
297// marshalExtensions marshals extension fields.
Joe Tsai378c1322019-04-25 23:48:08 -0700298func (o MarshalOptions) marshalExtensions(m pref.Message) error {
299 type entry struct {
300 key string
301 value pref.Value
302 desc pref.FieldDescriptor
Herbie Ong7b828bc2019-02-08 19:56:24 -0800303 }
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700304
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700305 // Get a sorted list based on field key first.
Joe Tsai378c1322019-04-25 23:48:08 -0700306 var entries []entry
307 m.Range(func(fd pref.FieldDescriptor, v pref.Value) bool {
308 if !fd.IsExtension() {
309 return true
310 }
Joe Tsai378c1322019-04-25 23:48:08 -0700311
Joe Tsai5ae10aa2019-07-11 18:23:08 -0700312 // For MessageSet extensions, the name used is the parent message.
Joe Tsaid4211502019-07-02 14:58:02 -0700313 name := fd.FullName()
Joe Tsai5ae10aa2019-07-11 18:23:08 -0700314 if messageset.IsMessageSetExtension(fd) {
315 name = name.Parent()
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700316 }
317
Joe Tsai378c1322019-04-25 23:48:08 -0700318 // Use [name] format for JSON field name.
319 entries = append(entries, entry{
320 key: string(name),
321 value: v,
322 desc: fd,
323 })
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700324 return true
325 })
326
327 // Sort extensions lexicographically.
328 sort.Slice(entries, func(i, j int) bool {
329 return entries[i].key < entries[j].key
330 })
331
332 // Write out sorted list.
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700333 for _, entry := range entries {
334 // JSON field name is the proto field name enclosed in [], similar to
335 // textproto. This is consistent with Go v1 lib. C++ lib v3.7.0 does not
336 // marshal out extension fields.
Damien Neil8c86fc52019-06-19 09:28:29 -0700337 if err := o.encoder.WriteName("[" + entry.key + "]"); err != nil {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700338 return err
339 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700340 if err := o.marshalValue(entry.value, entry.desc); err != nil {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700341 return err
342 }
343 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700344 return nil
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700345}